0

I would like to change the color of some points in a plot if its Euclidean distance to a cluster centroid coordinate is smaller or greater than to the other cluster centroid. I have made different attempts there is something missing that does not compile. I have created two tikz functions, dist1 and dist2 to each centroid, and try to use point meta in the addplot to change the color of the mark,

\documentclass{standalone}
\usepackage{pgfplots, pgfplotstable}
\usepackage{tikz}
\usetikzlibrary{positioning}
\usetikzlibrary{tikzmark,math}
\usetikzlibrary{arrows.meta}
\usepackage{calc}
\usepackage{filecontents}

\begin{filecontents*}{myplot.csv}
x,y
0.1566,1.8781
0.3431,1.5972
0.4492,1.714
0.6587,1.3417
0.7074,0.8094
1.1474,0.4845
1.3499,1.1533
1.8312,1.2761
2.1437,0.8622
2.2518,1.7449
\end{filecontents*}

\begin{document}

\begin{tikzpicture}
    \begin{axis}[        width=10cm,        height=10cm,        xlabel={$x$},        ylabel={$y$},        scatter/classes={            red={mark=square*,red},            blue={mark=triangle*,blue}        }    ]
    
    % Declare functions to compute distances to CC1 and CC2
    % Calculate distance to CC1 and CC2
    \tikzmath{
      coordinate \centroid1, \centroid2;
      \centroid1 = (3.5, 2.0);
      \centroid2 = (2.0, 1.0);
      function dist1(\x,\y) {
        return sqrt((\x - \centroid1.x)^2 + (\y - \centroid1.y)^2);
      };
      function dist2(\x,\y) {
        return sqrt((\x - \centroid2.x)^2 + (\y - \centroid2.y)^2);
      };
    }
    
    
    \addplot[
      mark=*,
      only marks,
      point meta=ifthenelse(dist1(\thisrow{x}, \thisrow{y}) < dist2(\thisrow{x}, \thisrow{y}), "red", "blue")
    ] table {myplot.csv};
    
    
    \end{axis}
\end{tikzpicture}

\end{document}

1 Answer 1

1

I do not know if it is easy to mix tikz math with pgfplots, and whether one can convince point meta to parse expressions and interpret the resulting string as a style. Most likely it is possible but I am unable to make this work. However, one can use the more low-level scatter/@pre marker code to achieve a conditional coloring. This code can be used to compare the distances of a given point from the two centroids, and set the style of the mark accordingly.

\documentclass{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.18}

\begin{filecontents*}[overwrite]{myplot.csv}
x,y
0.1566,1.8781
0.3431,1.5972
0.4492,1.714
0.6587,1.3417
0.7074,0.8094
1.1474,0.4845
1.3499,1.1533
1.8312,1.2761
2.1437,0.8622
2.2518,1.7449
\end{filecontents*}

\begin{document}

\begin{tikzpicture}
    \begin{axis}[width=10cm,height=10cm,xlabel={$x$},ylabel={$y$},
        declare function={cx1=1.5;cy1=2.0;cx2=2.0;cy2=1.0;
            dist(\x,\y,\u,\v)=sqrt((\x-\u)*(\x-\u)+(\y-\v)*(\y-\v));
            dist1(\x,\y)=dist(\x,\y,cx1,cy1);
            dist2(\x,\y)=dist(\x,\y,cx2,cy2);
            }    
        ]    
    
    \addplot[
      mark=*,
      only marks,
      scatter,
      visualization depends on={value \thisrow{x} \as \myx},
      visualization depends on={value \thisrow{y} \as \myy},
       scatter/@pre marker code/.code={%
         \pgfmathparse{int(dist1(\myx,\myy)<dist2(\myx,\myy)?1:0)}%
         \ifcase\pgfmathresult
            \tikzset{my mark/.style={mark=square*,red}}
         \or 
            \tikzset{my mark/.style={mark=triangle*,blue}}
         \fi
         \begin{scope}[my mark]
        },
        scatter/@post marker code/.code={\end{scope}}
    ] table[col sep=comma] {myplot.csv};
    \end{axis}
\end{tikzpicture}
\end{document}

enter image description here

Notice that I removed packages that are not in use and also changed the coordinates of one centroid, with the values given in the question all marks look the same because one distance is always smaller than the other.

You must log in to answer this question.

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