13

I am trying to plot a set of data points (scatter points not linked to each other), where each point has a different color. The color definition is given by predefined rgb values written in the same file that contains the data.

The following file serves as example:

\usepackage{filecontents}
\begin{filecontents}{test.dat}
    x   y   RED   GREEN   BLUE
    1   11  0.2    0.3    0.5
    2   14  0.3    0.3    0.4
    4   26  0.1    0.8    0.1
    3   39  0.0    0.1    0.9
\end{filecontents}

The x and y columns represent the position of the points I want to plot. The next three columns RED, GREEN and BLUE correspond to the associated color values in rgb format.

What I was trying so far, was to do:

\begin{document}

\pgfplotstableread{test.dat}\test
%number of points to be plotted
\pgfplotstablegetrowsof{\test}
\pgfmathsetmacro{\N}{\pgfplotsretval-1}  

\begin{tikzpicture}
\begin{axis}[%
    xmin=0, xmax=5,
    ymin=0, ymax=45,
    width=8cm,
    height=6cm,
    grid=both,
    xlabel=Xtest, 
    ylabel=Ytest,   
    ]
    \foreach \i in {0,...,\N}
    {
    \definecolor{testcolor}{rgb}{\thisrow{3}, \thisrow{4}, \thisrow{5}}   
    \addplot[scatter, 
        only marks,     
        scatter/use mapped color={draw=none,fill=testcolor},
    ] 
    table [x index = 0,y index = 1]{\test};
    }
\end{axis}
\end{tikzpicture}

\end{document}

But I am unable to fetch a single row value for the color definition. How can I do this ? I also looked at meta options, but the color is defined with a single value (linearly) and I need the three components in the color definition.

  • ugly alternative but if you're able to read only columns, you could try to write your *.dat file the following way: x | y | RED1 | GREEN1 | BLUE1 | RED2 | GREEN2 etc. where x and y are columns of n elements, but RED1, GREEN1 etc are columns of only 1 element... This would result in a file with 3*n+2 rows, but it might be better than nothing! – anderstood Aug 21 '14 at 6:04
  • @anderstood In this case I guess I would also need to split x and y as x1 | y1 | RED1 | GREEN1 | BLUE1 | x2 | y2 | ... It's not really what I'm looking for. There has to be a way to read the table row by row... – Nicolas Aug 21 '14 at 14:18
10

While it is possible to access table elements by means of \pgfplotstablegetelem{0}{RED}\of{\test}, I would recommend to move the code which defines colors into the \addplot command: pgfplots supports advanced scatter plots in which you can define how each scatter point it is to be drawn. This is more efficient in TeX.

A solution could be

\documentclass{standalone}

\usepackage{pgfplots}

\pgfplotsset{compat=1.9}

\begin{document}

\begin{tikzpicture}
\begin{axis}[%
    xmin=0, xmax=5,
    ymin=0, ymax=45,
    width=8cm,
    height=6cm,
    grid=both,
    xlabel=Xtest, 
    ylabel=Ytest,   
    ]
    \addplot[
        scatter,%
        scatter/@pre marker code/.code={%
            \edef\temp{\noexpand\definecolor{mapped color}{rgb}{\pgfplotspointmeta}}%
            \temp
            \scope[draw=mapped color!80!black,fill=mapped color]%
        },%
        scatter/@post marker code/.code={%
            \endscope
        },%
        only marks,     
        mark=*,
        point meta={TeX code symbolic={%
            \edef\pgfplotspointmeta{\thisrow{RED},\thisrow{GREEN},\thisrow{BLUE}}%
        }},
    ] 
    table {
    x   y   RED   GREEN   BLUE
    1   11  0.2    0.3    0.5
    2   14  0.3    0.3    0.4
    4   26  0.1    0.8    0.1
    3   39  0.0    0.1    0.9
    };
\end{axis}
\end{tikzpicture}
\end{document}

enter image description here

I used \addplot table {<inline data>}; to reduce the amount of code (which is, however, equivalent to \addplot ... table {\test};). The key points are:

  • I added mark=* since scatter does not necessarily assign a plot mark as default.
  • I used the keys pre marker code and post marker code to define the colors. This is precisely the same way how the default scatter implementation works. In our case, I used \definecolor{rgb}{\pgfplotspointmeta}, assuming that \pgfplotspointmeta contains something of sorts <R>,<G>,<B>.
  • Finally, the complicated point meta expression defines \pgfplotspointmeta in the expected way.
  • Note that we cannot simply insert \thisrow{RED},... into \definecolor here: \thisrow is only valid while pgfplots iterates over the table's row - and it does that just once when it surveys the input coordinates.
  • The macro \edef means "expanded definition": \edef\temp{...} defines \temp to contain the expanded argument. \noexpand means to not expand the following macro in this context.
  • point meta={TeX code symbolic={<code which defines \pgfplotspointmeta}} allows us to inject some TeX code to define a symbol - in our case a color triplet.
  • Thanks for the detailed answer and explanations. It worked smoothly ! – Nicolas Aug 24 '14 at 13:46
  • 1
    It seems that using \addplot ... table {\test}; returns an error (missing number, treated as zero <to be read again> t). I included the table as in the OP and loaded \pgfplotstableread{test.dat}{\data}, see hastebin.com/yafimoziru.tex. I must say I see no reason for this. – anderstood Oct 3 '15 at 18:30
  • I'm also getting the same "missing number, ..." error when loading from a file. Any suggestions please? – Niroshan Jul 14 at 13:11

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.