# Visualize data on a variable-radius graph/network

I am trying to visualize the output from a simulation model I have been working with. The simulation finds the steady-state solution to a system of differential equations on a variable-radius (and variable-edge-length) network/graph structure - think for example water and solute flow through a network of variable-radius pipes.

The branch center lines are straight but along the axial direction the radius and other variables e.g. the area-averaged solute concentration change.

I have a basic familiarity with pure tikz - less/not much at all with pgfplots. I have tried a hacky solution so far using tikz and pgfplotstable (to read in data) and have attached the result.

At the moment I draw each edge, perform the shading and then rotate/translate to its desired location. I don't care too much about whether the edges join nicely - it'd be nice but not essential. I've just left gaps for now. I note that the shading is not rotating properly at the moment - this is not my major problem as I have seen a couple of approaches to getting this working but I am a bit worried about the complexity of using canvas transforms as I also need to do a bunch of translations and different rotations for each edge. Note also that my reading in of the data is pretty hacky since I am using pure tikz to plot and wanted a smooth curve. There may be a better solution...

The most difficult problem I have is that I want the coloring to vary according to data read in from an external file - e.g. to represent the solute concentration at the local axial coordinate along a given edge. I have seen a tikz example which uses 'functional shading' (http://www.texample.net/tikz/examples/hsv-shading/) but it looks intimidatingly complex. I was wondering whether pgfplots might be a better option for this e.g. I have seen people refer to 'colormap' plots, but I am not sure whether I would still be able to draw the network structure as easily or whether I could use it together with some pure tikz etc.

So really my question is about how best to combine all the tools available from tikz and pgfplots to achieve all that I want. I can do bits with tikz but probably not all and I am not sure whether pgfplots could solve these issues or I should find another approach. Any advice would be much appreciated.

[Ah I realize I cannot post images because I am new to stackexchange. I have commented out the image. Sorry if that makes my question harder to understand!]

Example code:

\documentclass[10pt]{article}

\usepackage{pgf,tikz,pgfplots,pgfplotstable}
\begin{document}

\begin{tikzpicture}[scale=5]
\pgfplotstablegetrowsof{\data}
\pgfmathsetmacro{\rowindex}{\pgfplotsretval-1}
%-variables to build curves
\gdef\currentpath{}
\gdef\currentcoordlist{}
\foreach \srowindex in {0,...,\rowindex}{
%--get first coord pair
\pgfplotstablegetelem{\srowindex}{localcoord}\of{\data}
\pgfmathsetmacro{\x}{\pgfplotsretval}
\pgfmathsetmacro{\y}{\pgfplotsretval}
%--concatenate
\global\edef\currentpath{\currentpath--(\x,\y)}
\global\edef\currentcoordlist{\currentcoordlist (\x,\y)}
}
\begin{scope}[rotate around = {-90:(1,1)},shift={(1,1)}]
\path[fill,top color=blue, bottom color= green] (0.85,0)--(0,0) -- plot[smooth] coordinates \currentcoordlist;
\path[fill,top color=blue, bottom color= green] (0.85,0)--(0,0) -- plot[smooth,yscale={-1}]  coordinates \currentcoordlist;
\draw plot[smooth]  coordinates  \currentcoordlist;
\draw plot[smooth,yscale={-1}]  coordinates  \currentcoordlist;
\end{scope}
\begin{scope}[rotate around = {-45:(1,0)},shift={(1,0)}]
\path[fill,top color=blue, bottom color= green] (0.85,0)--(0,0) -- plot[smooth] coordinates \currentcoordlist;
\path[fill,top color=blue, bottom color= green] (0.85,0)--(0,0) -- plot[smooth,yscale={-1}]  coordinates \currentcoordlist;
\draw plot[smooth]  coordinates  \currentcoordlist;
\draw plot[smooth,yscale={-1}]  coordinates  \currentcoordlist;
\end{scope}
\begin{scope}[rotate around = {-90:(1.707,-0.707)},shift={(1.707,-0.707)}]
\path[fill,top color=blue, bottom color= green] (0.85,0)--(0,0) -- plot[smooth] coordinates \currentcoordlist;
\path[fill,top color=blue, bottom color= green] (0.85,0)--(0,0) -- plot[smooth,yscale={-1}]  coordinates \currentcoordlist;
\draw plot[smooth]  coordinates  \currentcoordlist;
\draw plot[smooth,yscale={-1}]  coordinates  \currentcoordlist;
\end{scope}
\begin{scope}[rotate around = {-135:(2.41,0)},shift={(2.41,0)}]
\path[fill,top color=blue, bottom color= green] (0.85,0)--(0,0) -- plot[smooth] coordinates \currentcoordlist;
\path[fill,top color=blue, bottom color= green] (0.85,0)--(0,0) -- plot[smooth,yscale={-1}]  coordinates \currentcoordlist;
\draw plot[smooth]  coordinates  \currentcoordlist;
\draw plot[smooth,yscale={-1}]  coordinates  \currentcoordlist;
\end{scope}
\end{tikzpicture}
\end{document}


## Data file: coord2.dat:

localcoord radius

0.0 0.1
0.1 0.1
0.2 0.15
0.3 0.1
0.4 0.2
0.5 0.1
0.6 0.05
0.7 0.15
0.8 0.1
0.85 0.1
%1.0 0.15

-
Welcome to Tex.SX. – Harish Kumar Jan 14 '13 at 1:49
Thanks Harish, and thanks Peter for editing my question to include the image :) – mjo Jan 14 '13 at 2:12
Great first question! – hpesoj626 Jan 14 '13 at 2:30

I understand that one key requirement is that the shading expands from the center line (symmetrically) to the boundaries, right?

This could be done by means of a patch plot of pgfplots combined with shader=interp in pgfplots:

\documentclass{standalone}

\usepackage{pgf,tikz,pgfplots,pgfplotstable}

% for patch type=bilinear
\usepgfplotslibrary{patchplots}

\begin{document}

\begin{tikzpicture}[scale=5]
\pgfplotstablegetrowsof{\data}
\pgfmathsetmacro{\rowindex}{\pgfplotsretval-1}
%-variables to build curves
\gdef\currentpath{}
\gdef\currentcoordlist{}
\gdef\Cim{}
\gdef\Rim{}
% R_{i-1} C_{i-1}
% Ri Ci
%
% and transform each two successive coords to TWO rectangular patches
% which have color data in square brackets
%
%
\foreach \srowindex in {0,...,\rowindex}{
%--get first coord pair
\pgfplotstablegetelem{\srowindex}{localcoord}\of{\data}
\pgfmathsetmacro{\Ci}{\pgfplotsretval}
\pgfmathsetmacro{\Ri}{\pgfplotsretval}
%--concatenate
\ifx\Cim\empty
\else
\def\cdataim{1}%
\def\cdatai{1}%
% \def\cdataim{\Rim}%
% \def\cdatai{\Ri}%
\global\edef\currentcoordlist{\currentcoordlist
(\Cim,\Rim) [\cdataim] (\Cim,0)  [0]
(\Ci,0)     [0]        (\Ci,\Ri) [\cdatai]
}%
\global\edef\currentcoordlist{\currentcoordlist
(\Cim,-\Rim) [\cdataim] (\Cim,0)   [0]
(\Ci,0)      [0]        (\Ci,-\Ri) [\cdatai]
}%
\fi
\global\let\Cim=\Ci
\global\let\Rim=\Ri
}
\global\edef\currentcoordlist{%
patch,
% patch type=rectangle,
patch type=bilinear,
mark=*,
]
coordinates {\currentcoordlist};
}%
\message{I got \meaning\currentcoordlist^^J}%

\def\image{%
\begin{axis}[
clip=false,
hide axis,
point meta=explicit,
x=1cm,
y=1cm,
mark size=0.05pt,
anchor=origin,
]
\currentcoordlist
\end{axis}
}%

\begin{scope}[rotate around = {-90:(1,1)},shift={(1,1)}]
\image
\end{scope}

\begin{scope}[rotate around = {-45:(1,0)},shift={(1,0)}]
\image
\end{scope}
\end{tikzpicture}
\end{document}


The key idea is to create rectangular patches. More precisely, for each consequtive two input coordinates, it creates two rectangular patches. The coordinates for these rectangular patches have to be provided in a specific sequence (namely the one in which you'd draw their boundaries). The square brackets after the coordinates is the color data: a scalar value which identifies the color at that point. In order to get a "right" color it is mapped into the current colormap. In my solution, the center always has cdata 0 whereas the edge has always 1.

EDIT Here is an alternative approach with smoother boundary curves. It is an attempt to get a similar effect as your smooth boundaries with minimum effort given the current feature set of pgfpltos.

It uses biquadratic shadings which are made up by three consecutive input points each. More precisely, points 0,1,2 make up the first biquadratic patch, points 2,3,4 the second biquadratic patch, and so on. This allows piecewise quadratic boundaries. However, due to the groups of size 3 which are unrelated, there are still sharp edges involved where the parables are connected:

\documentclass{standalone}

\usepackage{pgf,tikz,pgfplots,pgfplotstable}

% for patch type=bilinear
\usepgfplotslibrary{patchplots}

\begin{document}

\begin{tikzpicture}[scale=5]
0.0 0.1
0.1 0.1
0.2 0.15
0.3 0.1
0.4 0.2
0.5 0.1
0.6 0.05
0.7 0.15
0.8 0.1
0.9 0.1
1.0 0.15
}{\data}
\pgfplotstablegetrowsof{\data}
\pgfmathsetmacro{\rowindex}{\pgfplotsretval-1}
%-variables to build curves
\gdef\currentpath{}
\gdef\currentcoordlist{}
\gdef\Cimm{}
\gdef\Rimm{}
\gdef\Cim{}
\gdef\Rim{}
% R_{i-1} C_{i-1}
% Ri Ci
%
% and transform each two successive coords to TWO rectangular patches
% which have color data in square brackets
%
%
\gdef\srowindexmodthree{0}
\foreach \srowindex in {0,...,\rowindex}{
%--get first coord pair
\pgfplotstablegetelem{\srowindex}{localcoord}\of{\data}
\pgfmathsetmacro{\Ci}{\pgfplotsretval}
\pgfmathsetmacro{\Ri}{\pgfplotsretval}
%--concatenate
\ifnum\srowindexmodthree=2
\def\cdataimm{1}%
\def\cdataim{1}%
\def\cdatai{1}%
% \def\cdataim{\Rim}%
% \def\cdatai{\Ri}%
%
% (C[i-2], R[i-2])     (C[i-2],R[i-2]/2)         (C[i-2],0)
%
% (C[i-1], R[i-1])     (C[i-1], R[i-1]/2))     (C[i-1],0)
%
% (C[i],  R[i])    (C[i],R[i]/2)       (C[i], 0)
%
% in sequence
%  0    4     1
%
%  7    8     5
%
%  3    6     2
\global\edef\currentcoordlist{\currentcoordlist
(\Cimm,\Rimm) [\cdataimm]
(\Cimm,0)  [0]
(\Ci,0)     [0]
(\Ci,\Ri) [\cdatai]
%
(\Cimm,\Rimm/2) [0.5]
(\Cim,0)        [0]
(\Ci,\Ri/2)     [0.5]
(\Cim,\Rim)     [\cdataim]
%
(\Cim,\Rim/2)   [0.5]
}%
\global\edef\currentcoordlist{\currentcoordlist
(\Cimm,-\Rimm) [\cdataimm]
(\Cimm,0)  [0]
(\Ci,0)     [0]
(\Ci,-\Ri) [\cdatai]
%
(\Cimm,-\Rimm/2) [0.5]
(\Cim,0)        [0]
(\Ci,-\Ri/2)     [0.5]
(\Cim,-\Rim)     [\cdataim]
%
(\Cim,-\Rim/2)   [0.5]
}%
\fi
\global\let\Cimm=\Cim
\global\let\Rimm=\Rim
\global\let\Cim=\Ci
\global\let\Rim=\Ri
\count2=\srowindexmodthree\relax
\ifnum\count2=3
\count2=1 % do not start by 0, we reuse the first vertex
\fi
\xdef\srowindexmodthree{\the\count2 }%
}
\global\edef\currentcoordlist{%
patch,
% patch type=rectangle,
mark=*,
]
coordinates {\currentcoordlist};
}%
\message{I got \meaning\currentcoordlist^^J}%

\def\image{%
\begin{axis}[
clip=false,
hide axis,
point meta=explicit,
x=1cm,
y=1cm,
mark size=0.05pt,
anchor=origin,
]
\currentcoordlist
\end{axis}
}%

\begin{scope}[rotate around = {-90:(1,1)},shift={(1,1)}]
\image
\end{scope}

\end{tikzpicture}
\end{document}


The approach is slightly more involved because it regroups the input coordinates in a specific sequence. Furthermore, it works only if the number of input coordinates is suitable (I added a further point from your data file).

A final remark: the markers are optional; you can disable them if you uncomment the line with mark=*.

-
Thanks for the really awesome work! I'm a little embarrassed to say that I'm actually looking for the shading to be constant in the radial direction and vary in the axial direction. I think I can modify this to do that though. An alternative I have been working on involves plotting the color patch first then overlaying the curves. I'm not sure if it is sensible but it mostly works. The main thing remaining for me is to position the plots relative to each other - I need to keep reading the pgfplots manual for this. I will post what I have done so far as an answer if this is acceptable conduct? – mjo Jan 15 '13 at 23:43
Oops. In that case, your original solution might have been much more suitable than mine! Anyway, it was fun to create such graphics. And I found a regression in the developer version of pgfplots. – Christian Feuersänger Jan 16 '13 at 20:48
Thanks again Christian, this was still really helpful for me. – mjo Jan 17 '13 at 5:02

Regarding my comment on Christian's answer, here is a partial answer I have developed so far. I basically plot a rectangle color patch then plot the curved regions on top using stacked plots and use a white fill to remove the parts of the patch plot I don't want. The plot stacking means it is easiest to do in separate axes (I think?). The main thing that remains is to keep the correct groupings and overlaying of the plots. I imagine this should not be too difficult but I'm not 100% on how best to position various plots/axes. The outline of the background color does/doesn't show up depending on different viewers but I guess I could be more careful with defining the patched region/overlay.

\documentclass[10pt]{article}
\usepackage{pgf,tikz,pgfplots,pgfplotstable}
\pgfplotsset{compat=1.7}
\begin{document}

0.0 0.1
0.1 0.1
0.2 0.15
0.3 0.1
0.4 0.2
0.5 0.1
0.6 0.05
0.7 0.15
0.8 0.1
0.9 0.1
%1.0 0.15
}{\data}

\begin{tikzpicture}[scale=2]
%-coloured tube
%colouring
\begin{axis}[hide axis,x=100,y=100,z=100,xmin=-0.5, xmax= 1.5,ymin=-0.5,ymax=1.5,point meta=explicit]%,colorbar];
\end{axis}
%upper part
\begin{axis}[hide axis,x=100,y=100,z=100,xmin=-0.5, xmax= 1.5,ymin=-0.5,ymax=1.5,point meta=explicit,area style,stack plots=y]
\end{axis}
%lower part
\begin{axis}[hide axis,x=100,y=100,z=100,xmin=-0.5, xmax= 1.5,ymin=-0.5,ymax=1.5,point meta=explicit,area style,stack plots=y]
\end{axis}
%outline
\begin{axis}[hide axis,x=100,y=100,z=100,xmin=-0.5, xmax= 1.5,ymin=-0.5,ymax=1.5]
\end{axis}

%-rotated coloured tube
%colouring
\begin{axis}[hide axis,x=100,y=100,z=100,xmin=-0.5, xmax= 1.5,ymin=-0.5,ymax=1.5,point meta=explicit,transform canvas={rotate =60}]%,colorbar];
\end{axis}
%upper part of tube
\begin{axis}[hide axis,x=100,y=100,z=100,xmin=-0.5, xmax= 1.5,ymin=-0.5,ymax=1.5,point meta=explicit,area style,stack plots=y,transform canvas={rotate =60}]
\end{axis}
%lower part of tube
\begin{axis}[hide axis,x=100,y=100,z=100,xmin=-0.5, xmax= 1.5,ymin=-0.5,ymax=1.5,point meta=explicit,area style,stack plots=y,transform canvas={rotate =60}]
\addplot[smooth,draw=none] table[x=localcoord,y expr=-0.5] {\data} -- (axis cs:0.9,0) \closedcycle;
\end{axis}
%outline of tube
\begin{axis}[hide axis,x=100,y=100,z=100,xmin=-0.5, xmax= 1.5,ymin=-0.5,ymax=1.5,transform canvas={rotate =60}]
\end{axis}
\end{tikzpicture}
\end{document}


## Edit

Here is an updated version with relative positioning. I need to tidy some of the layering of the various plots and fully implement the reading in of the network structure and data but I think this will mostly work for me. If anyone has any advice for making it nicer I'd be happy to hear!

\documentclass[10pt]{article}
\usepackage{pgf,tikz,pgfplots,pgfplotstable}
\pgfplotsset{compat=1.7}
\begin{document}

%0.0 0.1
0.1 0.08
0.2 0.15
0.3 0.1
0.4 0.19
0.5 0.1
0.6 0.05
0.7 0.15
0.8 0.1
0.9 0.1
%1.0 0.15
}{\data}

\begin{tikzpicture}[x=100,y=100]
%nodes for connections
\draw (0,0) node[shape=circle,draw]{1};
\draw (1,-1.41) node[shape=circle,draw]{2};
\draw (1,0) node[shape=circle,draw]{3};
\draw (1.71,-0.71) node[shape=circle,draw]{4};
\draw (2.71,-0.71) node[shape=circle,draw]{5};
%-horizontal coloured tube
\begin{scope}[rotate around = {0:(0,0)},shift={(0,0)}]
\begin{axis}[hide axis,x=100,y=100,z=100,xmin=0, xmax= 1,ymin=-0.2,ymax=0.2,point meta=explicit,at={(0,0)},anchor=origin]%,colorbar];,transform canvas={rotate =60}
\end{axis}
%upper part of tube
\begin{axis}[hide axis,x=100,y=100,z=100,xmin=0, xmax= 1,ymin=-0.2,ymax=0.2,point meta=explicit,area style,stack plots=y,at={(0,0)},anchor=origin]
\end{axis}
%lower part of tube
\begin{axis}[hide axis,x=100,y=100,z=100,xmin=0, xmax= 1,ymin=-0.2,ymax=0.2,point meta=explicit,area style,stack plots=y,at={(0,0)},anchor=origin]
\addplot[smooth,draw=none] table[x=localcoord,y expr=-0.2] {\data} -- (axis cs:0.9,0) \closedcycle;
\end{axis}
%outline of tube
\begin{axis}[hide axis,x=100,y=100,z=100,xmin=0, xmax= 1,ymin=-0.2,ymax=0.2,at={(0,0)},anchor=origin]
\end{axis}
\end{scope}

%-rotated coloured tube
%colouring
\begin{scope}[rotate around = {-45:(1,0)},shift={(1,0)}]
\begin{axis}[hide axis,x=100,y=100,z=100,xmin=0, xmax= 1,ymin=-0.2,ymax=0.2,point meta=explicit,at={(0,0)},anchor=origin]%,colorbar];,transform canvas={rotate =60}
\end{axis}
%upper part of tube
\begin{axis}[hide axis,x=100,y=100,z=100,xmin=0, xmax= 1,ymin=-0.2,ymax=0.2,point meta=explicit,area style,stack plots=y,at={(0,0)},anchor=origin]
\end{axis}
%lower part of tube
\begin{axis}[hide axis,x=100,y=100,z=100,xmin=0, xmax= 1,ymin=-0.2,ymax=0.2,point meta=explicit,area style,stack plots=y,at={(0,0)},anchor=origin]
\addplot[smooth,draw=none] table[x=localcoord,y expr=-0.2] {\data} -- (axis cs:0.9,0) \closedcycle;
\end{axis}
%outline of tube
\begin{axis}[hide axis,x=100,y=100,z=100,xmin=0, xmax= 1,ymin=-0.2,ymax=0.2,at={(0,0)},anchor=origin]
\end{axis}
\end{scope}

%-rotated coloured tube 2
%colouring
\begin{scope}[rotate around = {45:(1,-1.41)},shift={(1,-1.41)}]
\begin{axis}[hide axis,x=100,y=100,z=100,xmin=0, xmax= 1,ymin=-0.2,ymax=0.2,point meta=explicit,at={(0,0)},anchor=origin]%,colorbar];,transform canvas={rotate =60}
\end{axis}
%upper part of tube
\begin{axis}[hide axis,x=100,y=100,z=100,xmin=0, xmax= 1,ymin=-0.2,ymax=0.2,point meta=explicit,area style,stack plots=y,at={(0,0)},anchor=origin]
\end{axis}
%lower part of tube
\begin{axis}[hide axis,x=100,y=100,z=100,xmin=0, xmax= 1,ymin=-0.2,ymax=0.2,point meta=explicit,area style,stack plots=y,at={(0,0)},anchor=origin]
\addplot[smooth,draw=none] table[x=localcoord,y expr=-0.2] {\data} -- (axis cs:0.9,0) \closedcycle;
\end{axis}
%outline of tube
\begin{axis}[hide axis,x=100,y=100,z=100,xmin=0, xmax= 1,ymin=-0.2,ymax=0.2,at={(0,0)},anchor=origin]
\end{axis}
\end{scope}

%-horizontal coloured tube 2
\begin{scope}[rotate around = {0:(0,0)},shift={(1.71,-0.71)}]
\begin{axis}[hide axis,x=100,y=100,z=100,xmin=0, xmax= 1,ymin=-0.2,ymax=0.2,point meta=explicit,at={(0,0)},anchor=origin]%,colorbar];,transform canvas={rotate =60}
\end{axis}
%upper part of tube
\begin{axis}[hide axis,x=100,y=100,z=100,xmin=0, xmax= 1,ymin=-0.2,ymax=0.2,point meta=explicit,area style,stack plots=y,at={(0,0)},anchor=origin]
\end{axis}
%lower part of tube
\begin{axis}[hide axis,x=100,y=100,z=100,xmin=0, xmax= 1,ymin=-0.2,ymax=0.2,point meta=explicit,area style,stack plots=y,at={(0,0)},anchor=origin]
\addplot[smooth,draw=none] table[x=localcoord,y expr=-0.2] {\data} -- (axis cs:0.9,0) \closedcycle;