3

I want to plot a bunch of curves on the same axis. They are all functions of two variables, let us call them x and p. I want to make plots y=f(x,p) with x as the x-axis variable for a fixed value of p for each curve. However, I would also like to color each of the curves according to a colormap based on the value of p. I have managed to do this manually (i.e., manually determining what should be the color of each curve and them writing dozens of \addplot commands), but I couldn't do it with a \foreach loop nor determine the color directly from the colormap. The following code is a MWE giving my current approach (which works, but it is extremely brute force and difficult to use for many curves) and my first approach at something slightly better, which fails for some reason I can't understand.

\documentclass[tikz]{standalone}
\usepackage{tikz}
\usepackage{pgfplots}
\pgfplotsset{
    discard if not/.style 2 args={
        x filter/.code={
            \ifdim\thisrow{#1}pt=#2pt
            \else
                \def\pgfmathresult{nan}
            \fi
        }
    }
}

\begin{filecontents*}{data.tsv}
parameter xvalue  yvalue
0   1   1
0   2   2
0   3   3
0.05   1   2
0.05   2   4
0.05   3   6
0.1   1   3
0.1   2   6
0.1   3   9
\end{filecontents*}

\begin{document}
\begin{tikzpicture}
\begin{axis}[
    point meta min = 0, 
    point meta max = 0.1,
    colormap={CM}{color=(red) color=(blue)},
    colorbar
]

\addplot[color=red, mark=*] table [x=xvalue, y=yvalue, meta=parameter, discard if not={parameter}{0}] {data.tsv};
\addplot[color=red!50!blue, mark=*] table [x=xvalue, y=yvalue, meta=parameter, discard if not={parameter}{0.05}] {data.tsv};
\addplot[color=blue, mark=*] table [x=xvalue, y=yvalue, meta=parameter, discard if not={parameter}{0.1}] {data.tsv};
\end{axis}
\end{tikzpicture}

\begin{tikzpicture}
\begin{axis}[
    point meta min = 0, 
    point meta max = 0.1,
    colormap={CM}{color=(red) color=(blue)},
    colorbar
]

\foreach \point in {0,0.05,0.1}{
    \pgfmathsetmacro{\percent}{\point*100}
    \addplot[color=red!\percent!blue, mark=*] table [x=xvalue, y=yvalue, meta=parameter, discard if not={parameter}{\point}] {data.tsv};
};
\end{axis}
\end{tikzpicture}
\end{document}

Brute force approach (first tikzpicture):

enter image description here

Current attempt at something better (second tikzpicture):

enter image description here

An ideal solution would allow me to simply specify the input file and colormap and let tex figure out the color of each curve and loop over the whole file.

2 Answers 2

5
+50

I suggest the following solution:

\documentclass{standalone}
\usepackage{pgfplots}

\begin{filecontents*}{data.tsv}
    parameter   xvalue  yvalue
    0       1   1
    0       2   2
    0       3   3

    0.05    1   2
    0.05    2   4
    0.05    3   6

    0.1     1   3
    0.1     2   6
    0.1     3   9
\end{filecontents*}

\begin{document}
\begin{tikzpicture}
    \begin{axis}[
            point meta min = 0,
            point meta max = 0.1,
            colormap={CM}{color=(red) color=(blue)},
            colorbar,
        ]

        \addplot[
            scatter,
            mesh,
            point meta=explicit,
            mark=*,
            empty line=jump,
        ] table [%
                x={xvalue},%
                y={yvalue},%
                meta=parameter,%
            ] {data.tsv};
        % }
    \end{axis}
\end{tikzpicture}
\end{document}

Compilation result

My proposed solution adresses multiple concerns:

  1. Coloring of lines and marks: use point meta=explicit to explicitely assign the meta value from the table source. The option mesh or scatter(for scatter plots only) make the plot use the mapped color.

  2. Automatically find all values of parameter: This might not be the most elegant solution, but if you have control over the generation of the data table, sort it by parameter and insert empty lines to segment it. The use oprion empty line=jump to insert a discontinuity into your plot, effectively splitting the representation into multiple different plots. This will not work, if you need a legend.

If my suggestion 2. does not fit your needs, just use the relebvant information from 1. and combine it with your foreach loop. This did still work in my test.

Caveat: I noticed some of my PDF viewers do not render the colors correctly. Please ensure it is not a display problem.

2
  • 1
    Nice answer (+1)! However, preamble can be shortened to \documentclass[margin=3mm]{standalone} \usepackage{pgfplots} \pgfplotsset{compat=1.18} \begin{filecontents*}{data.tsv} parameter xvalue yvalue ... \end{filecontents*}
    – Zarko
    Commented Apr 27, 2023 at 10:06
  • Thank you, you are right. I updated my code accordingly.
    – marc
    Commented Apr 27, 2023 at 10:14
1

You can achieve that using the scatter and scatter src options in your \addplot command. This way, you can map the parameter column directly to the colormap and avoid using a loop altogether.

Here's the MWE:

\documentclass{standalone}
\usepackage{pgfplots}
\pgfplotsset{
    discard if not/.style 2 args={
        x filter/.code={
            \ifdim\thisrow{#1}pt=#2pt
            \else
            \def\pgfmathresult{nan}
            \fi
        }
    }
}

\begin{filecontents*}{data.tsv}
    parameter xvalue  yvalue
    0   1   1
    0   2   2
    0   3   3
    0.05   1   2
    0.05   2   4
    0.05   3   6
    0.1   1   3
    0.1   2   6
    0.1   3   9
\end{filecontents*}

\begin{document}
    \begin{tikzpicture}
        \begin{axis}[
            point meta min = 0, 
            point meta max = 0.1,
            colormap={CM}{color=(red) color=(blue)},
            colorbar
            ]
            
            \foreach \point in {0,0.05,0.1}{
                \addplot[
                mesh, % for color interpolation along the line
                thin,
                point meta=\point, % set meta value for the line
                ] table [x=xvalue, y=yvalue, discard if not={parameter}{\point}] {data.tsv};
                % plot points separately
                \addplot[
                scatter, only marks, mark=*,
                scatter src=explicit, % use explicit value provided in the table for color mapping
                ] table [x=xvalue, y=yvalue, meta=parameter, discard if not={parameter}{\point}] {data.tsv};
            }
        \end{axis}
    \end{tikzpicture}
\end{document}

It will produce a plot with the correct colors, based on the parameter column mapped to the colormap.

This solution allows you to simply specify the input file and colormap, as you wanted. The code will automatically determine the color of each point and loop over the whole file.

By the way, you don't need empty lines. enter image description here

You must log in to answer this question.

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