14

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.

2
  • 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
    Commented Aug 21, 2014 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
    Commented Aug 21, 2014 at 14:18

1 Answer 1

11

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.
3
  • Thanks for the detailed answer and explanations. It worked smoothly !
    – Nicolas
    Commented Aug 24, 2014 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
    Commented Oct 3, 2015 at 18:30
  • I'm also getting the same "missing number, ..." error when loading from a file. Any suggestions please?
    – Niroshan
    Commented Jul 14, 2019 at 13:11

You must log in to answer this question.

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