# Conditional color and mark style for scatter plot in PGFPlots

I have a data file that has two columns each containing a class, one for color (QoI) and one for marker type (type). I would like points that have have the same QoI value be the same color, but have a different marker type for each type. There are only two different value for type, but several for QoI. I can get the colors working, but cannot figure out how to incorporate different marker styles. I couldn't find a way to use multiple values of meta, but perhaps there's another solution.

There are multiple plots that will be reading from multiple files, though for the MWE below they all read the same data. I just want to make sure the solution also works with groupplots.

# MWE

\documentclass[]{standalone}
\usepackage{tikz, pgf, pgfplots, pgfplotstable}
\usepgfplotslibrary{groupplots} % LATEX and plain TEX
\pgfplotsset{compat=1.15}
\usepgfplotslibrary{colorbrewer}
\pgfplotsset{cycle list/Dark2}
\usepackage{filecontents}
\begin{filecontents}{data.dat}
QoI model surrogate type outname QoI_group error_scaled
1 -1 -1.01224658575 training Q1 1 0.014956929466
1 -0.977952092966 -0.984618496392 training Q1 1 0.014956929466
2 0.53568190987 0.521776331357 training Q2 1 0.0158105026132
3 0.798208448928 0.789090773894 training Q3 1 0.044540998773
4 0.378407928561 0.326243792219 training Q4 1 0.0274695358287
4 0.355049936935 0.33464474407 training Q4 1 0.0274695358287
3 0.762183505103 0.681415197111 validation Q3 1 0.044540998773
3 0.822636091166 1.02086372811 validation Q3 1 0.044540998773
\end{filecontents}

\begin{document}
\begin{tikzpicture}[font=\small]
\tikzset{mark options={mark size=2, opacity=0.5}}
\begin{groupplot}[group style={group size=3 by 1, horizontal sep=1em},
width=7cm, height=7cm,
ymin=-1.2, ymax=1.2, xmin=-1.2, xmax=1.2,
scatter/classes={1={Dark2-A}, 2={Dark2-B}, 3={Dark2-C}, 4={Dark2-D}},
scatter,
scatter src=explicit symbolic,
]
\nextgroupplot[title={1}]
\addplot[only marks] table[x=model, y=surrogate, meta=QoI] {data.dat};
\nextgroupplot[title={2}, yticklabels={,,}]
\addplot[only marks] table[x=model, y=surrogate, meta=QoI] {data.dat};
\nextgroupplot[title={3}, yticklabels={,,}]
\addplot[only marks] table[x=model, y=surrogate, meta=QoI] {data.dat};
\end{groupplot}
\end{tikzpicture}
\end{document}


I added some comments to the code below to make more clear what I am trying to achieve. I think I was mistaken, I thought you could "cycle" through colors /based on/ the values of QoI. If that is not the case, do I have to explicitly define the scatter/classes? I could not find an example in the manual, so perhaps that is what is needed.

\documentclass[]{standalone}
\usepackage{tikz, pgf, pgfplots, pgfplotstable}
\usepgfplotslibrary{groupplots} % LATEX and plain TEX
\pgfplotsset{compat=1.15}
\usepgfplotslibrary{colorbrewer}
\usetikzlibrary{plotmarks}
\pgfplotsset{cycle list/Dark2}

\pgfdeclareplotmark{training}{
\pgfpathcircle{\pgfpoint{0pt}{0pt}}{2pt}\pgfusepathqfillstroke}
\pgfdeclareplotmark{validation}{
\pgfpathmoveto{\pgfpoint{-2pt}{-1pt}}
\pgfpathlineto{\pgfpoint{2pt}{-1pt}}
\pgfpathlineto{\pgfpoint{0pt}{2pt}}
\pgfpathlineto{\pgfpoint{-2pt}{-1pt}}
\pgfusepathqfillstroke}
\usepackage{filecontents}
\begin{filecontents}{data.dat}
QoI model surrogate type outname QoI_group error_scaled
1 -1 -1.01224658575 training Q1 1 0.014956929466                      % Color 1, mark style 1 (until "type"="validation")
1 -0.977952092966 -0.984618496392 training Q1 1 0.014956929466        % Color 1
2 0.53568190987 0.521776331357 training Q2 1 0.0158105026132          % Color 2
3 0.798208448928 0.789090773894 training Q3 1 0.044540998773          % Color 3
4 0.378407928561 0.326243792219 training Q4 1 0.0274695358287         % Color 4
4 0.355049936935 0.33464474407 training Q4 1 0.0274695358287          % Color 4
3 0.762183505103 0.681415197111 validation Q3 1 0.044540998773        % Color 3, mark style 2
3 0.822636091166 1.02086372811 validation Q3 1 0.044540998773         % Color 3, mark style 2
\end{filecontents}

\begin{document}
\begin{tikzpicture}[font=\small]
\tikzset{mark options={mark size=2, opacity=0.5}}
\begin{groupplot}[group style={group size=3 by 1, horizontal sep=1em},
width=7cm, height=7cm,
ymin=-1.2, ymax=1.2, xmin=-1.2, xmax=1.2,
% Commenting out scatter/classes removes meta color coding.
% Is there a way that I can automatically cycle the colors in scatter/classes
% so I don't have to define each explicitly, and so they'll reset for each \addplot+?
scatter/classes={1={Dark2-A}, 2={Dark2-B}, 3={Dark2-C}, 4={Dark2-D}},
scatter,
scatter src=explicit symbolic,
visualization depends on={value \thisrow{type}  \as \Type},
visualization depends on={value \thisrow{QoI}  \as \QoI},
scatter/@pre marker code/.append style={/tikz/mark=\Type},
% point meta=\coordindex     % This wasn't needed.
]
\nextgroupplot[title={1}]
\addplot[only marks] table[x=model, y=surrogate, meta=QoI] {data.dat};
\nextgroupplot[title={2}, yticklabels={,,}]
\addplot[only marks] table[x=model, y=surrogate, meta=QoI] {data.dat};
\nextgroupplot[title={3}, yticklabels={,,}]
\addplot[only marks] table[x=model, y=surrogate, meta=QoI] {data.dat};
\end{groupplot}
\end{tikzpicture}
\end{document}


An answer inspired by this answer and this answer. You only need to name your symbols somehow and use them like in the example of page 402 of the pgfplots manual. That is, you can use visualization depends on and then change the symbols with scatter/@pre marker code. UPDATE: I dropped the definition of the symbols, which I did for fun (and I stressed that). I do not think that discarding some part of the data and using \addplot over and over is very elegant.

\documentclass[]{standalone}
\usepackage{tikz, pgf, pgfplots, pgfplotstable}
\usepgfplotslibrary{groupplots} % LATEX and plain TEX
\pgfplotsset{compat=1.15}
\usepgfplotslibrary{colorbrewer}
\usetikzlibrary{plotmarks}
\pgfplotsset{colormap/Dark2,
cycle list/Dark2,
}

\pgfdeclareplotmark{training}{\pgfuseplotmark{*}}
\pgfdeclareplotmark{validation}{\pgfuseplotmark{square}}

\usepackage{filecontents}
\begin{filecontents}{data.dat}
QoI model surrogate type outname QoI_group error_scaled
1 -1 -1.01224658575 training Q1 1 0.014956929466                      % Color 1, mark style 1 (until "type"="validation")
1 -0.977952092966 -0.984618496392 training Q1 1 0.014956929466        % Color 1
2 0.53568190987 0.521776331357 training Q2 1 0.0158105026132          % Color 2
3 0.798208448928 0.789090773894 training Q3 1 0.044540998773          % Color 3
4 0.378407928561 0.326243792219 training Q4 1 0.0274695358287         % Color 4
4 0.355049936935 0.33464474407 training Q4 1 0.0274695358287          % Color 4
3 0.762183505103 0.681415197111 validation Q3 1 0.044540998773        % Color 3, mark style 2
3 0.822636091166 1.02086372811 validation Q3 1 0.044540998773         % Color 3, mark style 2
\end{filecontents}

\begin{document}
\begin{tikzpicture}[font=\small]
\tikzset{mark options={mark size=2, opacity=0.5}}
\begin{groupplot}[group style={group size=3 by 1, horizontal sep=1em},
width=7cm, height=7cm,
ymin=-1.2, ymax=1.2, xmin=-1.2, xmax=1.2,
scatter,
visualization depends on={value \thisrow{type}  \as \Type},
visualization depends on={value \thisrow{QoI}  \as \QoI},
scatter/@pre marker code/.append style={/tikz/mark=\Type},
point meta=explicit
]
\nextgroupplot[title={1}]
\addplot[only marks] table[x=model, y=surrogate, meta=QoI] {data.dat};
\nextgroupplot[title={2}, yticklabels={,,}]
\addplot[only marks] table[x=model, y=surrogate, meta=QoI] {data.dat};
\nextgroupplot[title={3}, yticklabels={,,}]
\addplot[only marks] table[x=model, y=surrogate, meta=QoI] {data.dat};
\end{groupplot}
\end{tikzpicture}
\end{document}


• Wow, thanks again! Is it possible to autocycle through the colors? It seems like I have to apply them through scatter/classes in order for it to take effect. – chasely Apr 17 '18 at 1:43
• @chasely As far as understand, these cycle lists allow you to switch colors from plot to plot, that is, each \addplot comes with a new color (see section 4.7.7 of the pgfplots manual). Or are you looking for the scatter/use mapped color = {color=mapped color} option? – user121799 Apr 17 '18 at 2:45
• It does indeed cycle through colors for each \addplot+, but can I cycle through colors for the meta flags without specifying each in scatter/classes? I need to specify scatter in order to get the \Type to trigger the mark style, but this also requires me to specify the scatter/classes for each item in \QoI. I can do this, but I have ~40 different classes (and growing) and would like to auto-generate these plots as I add more data. – chasely Apr 17 '18 at 12:28
• @chasely I still do not understand what you want, but I added a second code. Please have a look. The reason why I do not understand your question is that in my mind "cycle" clashes with the assumption that the color should depend on QoI. Or do you just want to define a color map? – user121799 Apr 17 '18 at 15:02
• I added a response in my original question. I do want the color to depend on QoI, but want to avoid explicitly defining each of the mappings from QoI->color via scatter/classes. I added a few comments to the updated code that should clarify what I am trying to achieve, but I am not sure if what I want is possible. – chasely Apr 17 '18 at 16:04

Here I present a solution where you don't have to define markers that match the "type" entry in your data file. If the default markers don't match your taste feel free to define your own (marker) cycle list using e.g. \pgfplotscreateplotcyclelist.

For details please have a look at the comments in the code.

% used PGFPlots v1.16
\begin{filecontents}{data.dat}
QoI model   surrogate   type        outname QoI_group   error_scaled
1   -1      -1.01224659 training    Q1      1           0.014956929466
1   -0.9780 -0.98461850 training    Q1      1           0.014956929466
2   0.53568 0.521776331 training    Q2      1           0.0158105026132
3   0.79821 0.789090774 training    Q3      1           0.044540998773
4   0.37841 0.326243792 training    Q4      1           0.0274695358287
4   0.35505 0.334644744 training    Q4      1           0.0274695358287
3   0.76218 0.681415197 validation  Q3      1           0.044540998773
3   0.82264 1.020863728 validation  Q3      1           0.044540998773
\end{filecontents}
\documentclass[border=5pt]{standalone}
\usepackage{pgfplots}
\usetikzlibrary{
pgfplots.colorbrewer,
pgfplots.groupplots,
}
\pgfplotsset{
colormap/Dark2,
% create a custom colormap from the colors of above loaded colormap ...
colormap={test}{
% using the first x colors, corresponding the max "QoI" value
% (to avoid an error if the number is too big)
samples of colormap=(4)
},
% we want to use "constant" colors in the colormap
% (i.e. don't interpolate between colors)
colormap access=const,
% create a filter for symbolic values
% (borrowed from <https://tex.stackexchange.com/a/58563/95441>)
% suppress LOG messages about the filtered points
x filter/.code={
\edef\tempa{\thisrow{#1}}
\edef\tempb{#2}
\ifx\tempa\tempb
\else
\def\pgfmathresult{inf}
\fi
},
}
}
\begin{document}
\begin{tikzpicture}[
font=\small,
]
\begin{groupplot}[
group style={
group size=3 by 1,
horizontal sep=1em,
% (added this option, so you don't have to provide the
%  yticklabels' at the \nextgroupplot' options)
yticklabels at=edge left,
},
width=7cm,
height=7cm,
ymin=-1.2,
ymax=1.2,
xmin=-1.2,
xmax=1.2,
scatter,
% ---------------------------------------------------------------------
% moved common options here
/tikz/only marks,
table/x=model,
table/y=surrogate,
table/meta=QoI,
point meta=explicit,
% ---------------------------------------------------------------------
]
\nextgroupplot[title={1}]
% cycle through the possible "type" entries
% (because every new \addplot' command uses the next entry in the
%  cycle list', the markers are changed as you wish)
\foreach \i in {training,validation} {
}
\nextgroupplot[title={2}]
\foreach \i in {training,validation} {

• This is an elegant solution. However I get a note when compiling: "NOTE: coordinate (a,b) has been dropped because it is unbounded (in x). (see also unbounded coords=jump). Where a,b are the x and y coordinates. The warning goes away by adding in unbounded coords=jump, but I don't see why this would show up. I'm using PGFPlots 1.15 (On MacTex 2017). Perhaps this isn't an issue with 1.16. In any case, it does plot all the data even with the warning. – chasely Apr 17 '18 at 20:09