3

My aim is to create a polar plot from a data set, where an additional data column defines the fill color radially out from the center. Can this be done in PGFPlots?

In the example below, I create a three column data set where x is the angle, y is a measured value, and z is an additional measured value I would like to include through coloring. The example compiles, and the marker color is changed in the scatter plot. In terms of coloring, this is what I am aiming for:

\documentclass{standalone}
\usepackage{pgfplots}

\usepgfplotslibrary{polar}

\usepackage{filecontents}
\def\mydata{mydata.csv}
\begin{filecontents*}{\mydata}
    x,y,z
    -80,5,0
    -60,6,1
    -40,2,2
    -20,7,3
    0,5,4
    20,3,5
    40,7,6
    60,3,7
    80,4,8
\end{filecontents*}

\begin{document}

\begin{tikzpicture} 

\begin{polaraxis}[
    % x-axis
    xtick={-90, -45, 0, 45, 90},
    % y-axis
    ytick = {40, 80},
    % limits
    domain = -90:90, xmin = -90, xmax = 90,
    % colors
    colormap/viridis,
    point meta min = 0, point meta max = 8,
]
\addplot[point meta = explicit, scatter, polar comb] table [x=x, y=y, meta=z, col sep=comma] {\mydata};
\end{polaraxis}

\end{tikzpicture}

\end{document}

Instead of coloring the markers, my aim is to fill with that color from the origin to the y-value, rather like a pie chart. 'Polar comb' looks promising, but I am not able to color the comb line (only the marker) and the comb also does not fill between lines (i.e. fill the whole segment). I have tried various [fill=...] options in \addplot but I can only get a single color fill.

  • 1
    How are the segments defined/exactly what kind of regions do you want filled? Pie slices centered on the defined coordinate? Triangles with vertices at neighbouring points and the origin? – Torbjørn T. May 30 at 21:42
  • The measurements, B, are at specific angles, A, with a step, D, between. The segment I want to color is A +/- D/2 from the origin to radial position B. The overall color effect should be something like the right hand image in https://xkcd.com/2031/ if D is small enough. – David H. May 31 at 9:11
2

I don't think pgfplots have anything like that built-in. One can do it manually, as in the example below, by reading the values from the table with the macros from pgfplotstable, and using plain old TikZ to draw the diagram. I got the method for extracting a color from a colormap from https://tex.stackexchange.com/a/340346.

\documentclass{standalone}
\usepackage{xfp}
\usepackage{pgfplotstable} 
\usepackage{filecontents}
\def\mydata{mydata.csv}
\begin{filecontents*}{\mydata}
    x,y,z
    -80,5,0
    -60,6,1
    -40,2,2
    -20,7,3
    0,5,4
    20,3,5
    40,7,6
    60,3,7
    80,4,8
\end{filecontents*}



\pgfplotstableread[col sep=comma]{\mydata}\loadedtable

\begin{document}

\begin{tikzpicture}[
  % radii are normalized to [0,1], so the scale will in effect set the radius of the longest slice
  scale=5,
  % from https://tex.stackexchange.com/a/340346
  % Defines the colormap
  /pgfplots/colormap/viridis,
  slice/.style={/utils/exec={
     % Defines a color "mapped color"
     \pgfplotscolormapdefinemappedcolor{#1}},
     fill=mapped color
  }
 ]

% define half angle step 
\pgfmathsetmacro\Dhalf{10}

% get number of data rows in table
\pgfplotstablegetrowsof{\mydata}
\pgfmathtruncatemacro{\Nrows}{\pgfplotsretval-1}

% find min/max of z-column
\pgfmathsetmacro\ZMax{-1e3}
\pgfmathsetmacro\ZMin{1e3}
% https://tex.stackexchange.com/a/252360/
\pgfplotstableforeachcolumnelement{z}\of\loadedtable\as\cellValue{\pgfmathsetmacro{\ZMax}{max(\ZMax,\cellValue)}}
\pgfplotstableforeachcolumnelement{z}\of\loadedtable\as\cellValue{\pgfmathsetmacro{\ZMin}{min(\ZMin,\cellValue)}}
% calculate range of z-values
\pgfmathsetmacro\Zrange{\ZMax-\ZMin}

% find max radius
\pgfmathsetmacro\RMax{0}
\pgfplotstableforeachcolumnelement{y}\of\loadedtable\as\cellValue{\pgfmathsetmacro{\RMax}{max(\RMax,\cellValue)}}


% draw axis and ticks
% if you want these on top of the circle sectors, move the code to the end
\pgfmathsetmacro\AxisRadius{1.1}
\draw (0,0) -- (0,\AxisRadius) arc[start angle=90,delta angle=-180,radius=\AxisRadius] -- cycle;
\foreach \A in {-90,-45,...,90}
   \draw [very thin, gray] (0,0) -- (\A:\AxisRadius*1cm+1pt) node [black, circle,anchor=\A+180]  {$\A$};


% loop over the table
\foreach \N in {0,...,\Nrows}{
   % read x-value from table
  \pgfplotstablegetelem{\N}{x}\of\loadedtable
  \pgfmathsetmacro{\tmpX}{\pgfplotsretval}
  % read y-value from table
  \pgfplotstablegetelem{\N}{y}\of\loadedtable
  \pgfmathsetmacro{\tmpY}{\pgfplotsretval/\RMax}
  % read z-value from table
  \pgfplotstablegetelem{\N}{z}\of\loadedtable
  \pgfmathsetmacro{\tmpZ}{\pgfplotsretval}
  % \pgfplotscolormapdefinemappedcolor takes a number between 0 and 1000 as input. 
  % scale the given z-value based on the range of values
  \newcommand{\tmpClr}{\fpeval{(\tmpZ-\ZMin)/\Zrange*1000}}

  % make the slice
  \fill [slice=\tmpClr] (0,0) -- (\tmpX-\Dhalf:\tmpY) arc[start angle=\tmpX-\Dhalf, delta angle=2*\Dhalf, radius=\tmpY] -- cycle;
}


\end{tikzpicture}
\end{document}

enter image description here

Round 2

\documentclass{standalone}
\usepackage{xfp}
\usepackage{pgfplotstable} 
\usepackage{filecontents}
\def\mydata{mydata.csv}
\begin{filecontents*}{\mydata}
    x,y,z
    -80,5,0
    -60,6,1
    -40,2,2
    -20,7,3
    0,5,4
    20,3,5
    40,7,6
    60,3,7
    80,4,8
\end{filecontents*}



\pgfplotstableread[col sep=comma]{\mydata}\loadedtable

\begin{document}

\begin{tikzpicture}[
  % radii are normalized to [0,1], so the scale will in effect set the radius of the longest slice
  scale=5,
  % from https://tex.stackexchange.com/a/340346
  % Defines the colormap
  /pgfplots/colormap/viridis,
  slice/.style={/utils/exec={
     % Defines a color "mapped color"
     \pgfplotscolormapdefinemappedcolor{#1}},
     fill=mapped color
  }
 ]

% define half angle step 
\pgfmathsetmacro\Dhalf{10}

% get number of data rows in table
\pgfplotstablegetrowsof{\mydata}
\pgfmathtruncatemacro{\Nrows}{\pgfplotsretval-1}

% find min/max of z-column
\pgfmathsetmacro\ZMax{-1e3}
\pgfmathsetmacro\ZMin{1e3}
% https://tex.stackexchange.com/a/252360/
\pgfplotstableforeachcolumnelement{z}\of\loadedtable\as\cellValue{\pgfmathsetmacro{\ZMax}{max(\ZMax,\cellValue)}}
\pgfplotstableforeachcolumnelement{z}\of\loadedtable\as\cellValue{\pgfmathsetmacro{\ZMin}{min(\ZMin,\cellValue)}}
% calculate range of z-values
\pgfmathsetmacro\Zrange{\ZMax-\ZMin}

% find max radius
\pgfmathsetmacro\RMax{0}
\pgfplotstableforeachcolumnelement{y}\of\loadedtable\as\cellValue{\pgfmathsetmacro{\RMax}{max(\RMax,\cellValue)}}


% draw axis and ticks
% if you want these on top of the circle sectors, move the code to the end
\pgfmathsetmacro\AxisRadius{1.05}
\draw (0,0) -- (0,\AxisRadius) arc[start angle=90,delta angle=-180,radius=\AxisRadius] -- cycle;
\foreach \A in {-80,-60,...,90}
   \draw [very thin, gray] (0,0) -- (\A:\AxisRadius*1cm+1pt) node [black, circle,anchor=\A+180]  {$\A$};


% loop over the table
\foreach [evaluate={\M=int(\N+1);\O=int(\N-1);}] \N in {0,...,\Nrows}{
   % read x-value from table
  \pgfplotstablegetelem{\N}{x}\of\loadedtable
  \pgfmathsetmacro{\tmpX}{\pgfplotsretval}
  % read y-value from table
  \pgfplotstablegetelem{\N}{y}\of\loadedtable
  \pgfmathsetmacro{\Rmid}{\pgfplotsretval/\RMax}
  % read z-value from table
  \pgfplotstablegetelem{\N}{z}\of\loadedtable
  \pgfmathsetmacro{\tmpZ}{\pgfplotsretval}
  % \pgfplotscolormapdefinemappedcolor takes a number between 0 and 1000 as input. 
  % scale the given z-value based on the range of values
  \newcommand{\tmpClr}{\fpeval{(\tmpZ-\ZMin)/\Zrange*1000}}

  \ifnum \N>0
     \pgfplotstablegetelem{\O}{y}\of\loadedtable
     \pgfmathsetmacro{\YPre}{\pgfplotsretval/\RMax}

     \pgfmathsetmacro\Rpre{0.5*sqrt(\Rmid*\Rmid + \YPre*\YPre + 2*\Rmid*\YPre*cos(\Dhalf*2))}

     \pgfmathsetmacro\AnglePre{atan2(0.5*(\Rmid*sin(\tmpX) + \YPre*sin(\tmpX-\Dhalf*2)), 0.5*(\Rmid*cos(\tmpX) + \YPre*cos(\tmpX-\Dhalf*2)))}

  \fi
  \ifnum \N<\Nrows
     \pgfplotstablegetelem{\M}{y}\of\loadedtable
     \pgfmathsetmacro{\YPost}{\pgfplotsretval/\RMax}
     \pgfmathsetmacro\Rpost{sqrt(\Rmid*\Rmid + \YPost*\YPost + 2*\Rmid*\YPost*cos(\Dhalf*2))/2}

     \pgfmathsetmacro\AnglePost{atan2(0.5*(\Rmid*sin(\tmpX) + \YPost*sin(\tmpX+\Dhalf*2)), 0.5*(\Rmid*cos(\tmpX) + \YPost*cos(\tmpX+\Dhalf*2)))}

  \fi

  \ifnum \N=0
      \fill [slice=\tmpClr] (0,0) -- (\tmpX:\Rmid) -- (\AnglePost:\Rpost) -- cycle;
  \else
     \ifnum \N=\Nrows
       \fill [slice=\tmpClr] (0,0) -- (\tmpX:\Rmid) -- (\AnglePre:\Rpre) -- cycle;
     \else
       \fill [slice=\tmpClr] (0,0) -- (\AnglePre:\Rpre) -- (\tmpX:\Rmid) -- (\AnglePost:\Rpost) -- cycle;
     \fi
   \fi
}

\end{tikzpicture}
\end{document}

enter image description here

  • Thank you. I have tried this with my real data and it works well. Is it simple to modify this to color in the same way but instead of filling the full segment, connecting the data points together and filling up to the connecting lines? (By this, I mean the lines you get if you replaced [...scatter, polar comb] in my original example with [...mesh]). – David H. Jun 1 at 15:09
  • @DavidH. So essentially a series of triangles with differing colors? Which of the vertices should determine the color of the triangle? – Torbjørn T. Jun 1 at 16:05
  • The aim here is to smooth off the transition between the segments (to make it more like a polar plot than a pie chart). The color would be defined as before and spread to the midway points between each vertex and its neighboring vertices. – David H. Jun 1 at 17:06
  • 1
    @DavidH. Like that? – Torbjørn T. Jun 2 at 9:36
  • Excellent. Just what I was after. Many thanks for your help. – David H. Jun 3 at 7:57

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.