12

I'd like to adopt a consistent color scheme for my document (and preferably further documents) for all TikZ/PGF-based graphics and text highlights.

More specifically, I'd like to start off by selecting a contiguous color range (i.e. a pgfplots colormap), and pick several individual colors via sample points from that color range. Then I want to arrange these individual colors in sequential lists (such as pgfplots cycle list, TikZ/PGF style sheet and potentially xcolor colorseries), but also make them individually accessible via commands like \mycolor3 or \mycolors{3}. Overall, I am looking for an approach where the only inputs are the color range and the sample points (preferably in range [0,1] as opposed to pgfplots cycle list ranges [0,1000]), and all the rest is then "generated" automatically.

Please note that I am looking for an approach flexible enough to add further representations of my colors later on, if I need such. The only common ground I'd like to assume is color representation using the xcolor package due to its wide support in many other packages.

I experimented a little using the etoolbox package, but so far to no avail. The xpase package seems to be useful as well, but so far I wasn't able to make good use of it by myself.

My question probably is rather unspecific right now, but perhaps some discussion would help me to actually point down what exactly I am looking for.

EDIT:

Here is an example, showing some things I want to do:

\documentclass[a4paper]{article}

\usepackage{pgfplotstable}
\pgfplotsset{compat=1.18}
\usetikzlibrary{datavisualization}

% (A) PGFPLOTS color map
\newcommand{\MyColorMap}{viridis}

% (B) values in [0,1] to sample from the color map
\newcommand{\defineMyColorSample}[2]{%
    \expandafter\newcommand\csname MyColorSample:#1\endcsname{#2}%
}
\newcommand{\MyColorSample}[1]{\csname MyColorSample:#1\endcsname}
\defineMyColorSample{1}{0.0}
\defineMyColorSample{2}{0.5}
\defineMyColorSample{3}{0.25}
\defineMyColorSample{4}{0.75}
\newcommand{\MyColorSamples}{
    \MyColorSample{1},
    \MyColorSample{2},
    \MyColorSample{3},
    \MyColorSample{4}
}

% (C) color map samples based on the samples above but mapped to range [0,1000]
\newcommand{\defineMyColorMapSample}[2]{%
    \expandafter\newcommand\csname MyColorMapSample:#1\endcsname{#2}%
}
\newcommand{\MyColorMapSample}[1]{\csname MyColorMapSample:#1\endcsname}
\newcommand{\MyColorCalc}[1]{\directlua{ tex.write(#1) }}
\defineMyColorMapSample{1}{\MyColorCalc{1000 * \MyColorSample{1}}}
\defineMyColorMapSample{2}{\MyColorCalc{1000 * \MyColorSample{2}}}
\defineMyColorMapSample{3}{\MyColorCalc{1000 * \MyColorSample{3}}}
\defineMyColorMapSample{4}{\MyColorCalc{1000 * \MyColorSample{4}}}
\newcommand{\MyColorMapSamples}{
    \MyColorMapSample{1},
    \MyColorMapSample{2},
    \MyColorMapSample{3},
    \MyColorMapSample{4}
}

% (D) individual colors based on sample points of colomap
% ???
% add some dummies for now
\newcommand{\defineMyColor}[2]{%
    \expandafter\newcommand\csname MyColor:#1\endcsname{#2}%
}
\newcommand{\MyColor}[1]{\csname MyColor:#1\endcsname}
\defineMyColor{1}{red}
\defineMyColor{2}{green}
\defineMyColor{3}{blue}
\defineMyColor{4}{yellow}
\newcommand{\MyColors}{
    \MyColor{1},
    \MyColor{2},
    \MyColor{3},
    \MyColor{4}
}

% (E) PGFPLOTS cycle list
\pgfplotscreateplotcyclelist{MyColorCycleList}{
    [colors of colormap={\MyColorMapSamples} of \MyColorMap]
}

% (F) TikZ/PGF style sheet
\pgfkeys{
    /pgf/data visualization/style sheets/MyStyle/.cd,
    % All these styles have the above prefix.
    1/.style={\MyColor{1}},
    2/.style={\MyColor{2}},
    3/.style={\MyColor{3}},
    4/.style={\MyColor{4}},
    default style/.style={black}
}

\begin{document}

\section{colored text}
\textcolor{\MyColor{3}}{This text} uses \colorbox{\MyColor{4}}{my colors}.
\begin{enumerate}
    \item \textcolor{\MyColor{1}}{first color}
    \item \textcolor{\MyColor{2}}{second color}
    \item \textcolor{\MyColor{3}}{third color}
    \item \textcolor{\MyColor{4}}{fourth color}
\end{enumerate}

\section{PGFPLOTS cycle list}
% adapted from PGFPLOTS manual (v1.18.1) section 4.7.7
\begin{tikzpicture}
\begin{axis}[
    stack plots=y,stack dir=minus,
    cycle list name=MyColorCycleList,
    fatline/.style={line width=5pt},
]
    \addplot+[fatline] coordinates {(0,1) (0.5,1) (1,1)};
    \addplot+[fatline] coordinates {(0,1) (0.5,1) (1,1)};
    \addplot+[fatline] coordinates {(0,1) (0.5,1) (1,1)};
    \addplot+[fatline] coordinates {(0,1) (0.5,1) (1,1)};
\end{axis}
\end{tikzpicture}

\section{TikZ data visaulization}
% adapted from TikZ/PGF manual (v3.1.9a) section 84.4.2
\tikz \datavisualization [
    school book axes, all axes={length=0.5\textwidth},
    visualize as line=1,
    visualize as line=2,
    visualize as line=3,
    style sheet=MyStyle]
data point [x=0, y=0, set=1]
data point [x=2, y=2, set=1]
data point [x=0, y=1, set=2]
data point [x=2, y=1, set=2]
data point [x=0.5, y=1.5, set=3]
data point [x=2.25, y=1.75, set=3];

\end{document}

output

The only "inputs" I'd like to enter are the colormap (cf. (A) in preamble) and a list of sample values (cf. (B) in preamble). In the example, however, definition of the latter is a bit cumbersome as I'd prefer something like

\newcommand{\MyColorSamples}{0.0, 0.5, 0.25, 0.75}

Furthermore, mapping the samples from [0,1] to [0,1000] currently involves Lua code (cf. (C) in preamble), which I'd like to omit.

Next, I have no idea how to extract sampled colors from the pgfplots colormap and make them available as basic xcolor colors (cf. (D) in preamble). Moreover, I'd like to have my colors in some kind of colorseries, so I can use the awesome expressions of xcolor (e.g. !!+), although this is optional for me.

While defining a pgfplots cyclelist is quite straight-forward (cf. (E) in preamble), a TikZ/PGF style sheet (cf. (F) in preamble) depends on the colors from (D).

Overall, my code so far is very verbose and whenever the length of the sample list (cf. (B)) is changed, the entire code needs to be adapted. For this reason I'd like to implement everything in loops, but I could not figure out how to do that properly yet.

4
  • The question is indeed rather unspecific and therefore difficult to answer. Maybe you can create a small document with an outline of what you want to specify and how, and add some further commands that use this specification, with some syntax that doesn't work currently but that shows your general idea. Also specify exactly what the output of each part of the code should be, like "this should generate a graph with blue and red lines" or something. Then it would probably be more clear what you want and what the best way is to achieve it (or that it is practically impossible, for example).
    – Marijn
    Dec 14, 2022 at 16:02
  • I have not understood anything. What is wrong with making a few rgb definitions where you can set as you want in a 0-1 scale each basic color? e.g., a "foo, bar, baz" color scheme from a dark blue to a pale green simply changing the "g" values from 0.3 to 0.9: \documentclass{article} \usepackage{xcolor} \definecolor{foo}{rgb}{.1,.3,.6} \definecolor{bar}{rgb}{.1,.6,.6} \definecolor{baz}{rgb}{.1,.9,.6} \begin{document} \begin{testcolors}[rgb,RGB,HTML] \testcolor{foo} \testcolor{bar} \testcolor{baz} \end{testcolors} \end{document}
    – Fran
    Dec 15, 2022 at 6:51
  • @Marijn I've added a rather lengthy example and some more comments on that. I hope this helps.
    – Thargon
    Dec 16, 2022 at 13:37
  • @Fran I want to use a colormap and a list of sample points as the only inputs. All the rest should be generated automatically. Therefore just using \definecolor as you proposed is not possible in my case.
    – Thargon
    Dec 16, 2022 at 13:40

1 Answer 1

11

After some painful trial and error, I was able to figure out a solution myself:

\documentclass[a4paper]{article}

\usepackage{pgfplotstable}
\pgfplotsset{compat=1.18}
\usetikzlibrary{datavisualization}
\usepackage{etoolbox}
\usepackage{calculus}

% (A) "input" definitions
\newcommand{\MyColorMapName}{colormap/viridis}
\newcommand{\MyColorSamples}{0.5, 0.0, 1.0, 0.25, 0.75}

% (B) retrieve number of sample points and make individual values availabe via \MyColorSample{<i>} command
\newcommand*{\MyColorSample}[1]{\csname MyColorSample:#1\endcsname}
\newcounter{MyColorSamplesSize}
\renewcommand*{\do}[1]{%
    \stepcounter{MyColorSamplesSize}%
    \listxadd{\MyColorSampleIDs}{\theMyColorSamplesSize}%
    \expandafter\def\csname MyColorSample:\theMyColorSamplesSize\endcsname{#1}%
}
\expandafter\docsvlist\expandafter{\MyColorSamples}

% (C) caclulate color map samples based on \MyColorSamples but mapped to range [0,1000]
\def\MyColorMapSamples{}
\newcommand*{\MyColorMapSample}[1]{\csname MyColorMapSample:#1\endcsname}
\renewcommand*{\do}[1]{
    \MULTIPLY{\MyColorSample{#1}}{1000.0}{\val}%
    \FLOOR{\val}{\valf}%
    \ifstrequal{\val}{\valf}{\edef\val{\val .0}}%
    \expandafter\edef\csname MyColorMapSample:#1\endcsname{\val}%
    \edef\MyColorMapSamples{\MyColorMapSamples\MyColorMapSample{#1}\ifnumcomp{#1}{=}{\theMyColorSamplesSize}{}{, }}%
}
\dolistloop{\MyColorSampleIDs}

% (D) define individual colors based on sample points of colormap
\colorlet{DefaultColor}{.} % save current default color
\newcommand*{\MyColor}[1]{MyColor#1}
\renewcommand*{\do}[1]{%
    \pgfplotsset{color of colormap=\MyColorMapSample{#1} of \MyColorMapName}%
    \colorlet{MyColor#1}{.}
}
\dolistloop{\MyColorSampleIDs}
\colorlet{.}{DefaultColor} % restore default color


% (E) define PGFPLOTS cycle list
\pgfplotscreateplotcyclelist{MyColorCycleList}{
    [colors of colormap={\MyColorMapSamples} of \MyColorMapName]
}

% (F) define TikZ/PGF style sheet
\renewcommand*{\do}[1]{%
    #1/.style={\MyColor{#1}, line width=2pt},
}
\edef\MyStyle{\noexpand\pgfkeys{
    /pgf/data visualization/style sheets/MyStyle/.cd,
    \dolistloop{\MyColorSampleIDs}
    default style/.style={black,line width=5pt}
}}
\MyStyle

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{document}

\section{color map}
selected color map: \texttt{\MyColorMapName}\\
\pgfplotscolorbardrawstandalone[
    \MyColorMapName,
    colorbar horizontal
]

\section{color boxes and colored text}
\theMyColorSamplesSize\ color samples have been defined:
\begin{enumerate}
    \renewcommand*{\do}[1]{
        \item \colorbox{\MyColor{#1}}{\textcolor{-\MyColor{#1}}{colored box with complementary text color}}
    }
    \dolistloop{\MyColorSampleIDs}
\end{enumerate}

\section{PGFPLOTS cycle list}
% adapted from PGFPLOTS manual (v1.18.1) section 4.7.7
\begin{tikzpicture}
\begin{axis}[
    stack plots=y,stack dir=minus,
    cycle list name=MyColorCycleList,
    fatline/.style={line width=2pt},
]
    \addplot+[fatline] coordinates {(0,1) (0.5,1) (1,1)};
    \addplot+[fatline] coordinates {(0,1) (0.5,1) (1,1)};
    \addplot+[fatline] coordinates {(0,1) (0.5,1) (1,1)};
    \addplot+[fatline] coordinates {(0,1) (0.5,1) (1,1)};
    \addplot+[fatline] coordinates {(0,1) (0.5,1) (1,1)};
    \addplot+[fatline] coordinates {(0,1) (0.5,1) (1,1)};
    \addplot+[fatline] coordinates {(0,1) (0.5,1) (1,1)};
    \addplot+[fatline] coordinates {(0,1) (0.5,1) (1,1)};
    \addplot+[fatline] coordinates {(0,1) (0.5,1) (1,1)};
    \addplot+[fatline] coordinates {(0,1) (0.5,1) (1,1)};
    \addplot+[fatline] coordinates {(0,1) (0.5,1) (1,1)};
    \addplot+[fatline] coordinates {(0,1) (0.5,1) (1,1)};
    \addplot+[fatline] coordinates {(0,1) (0.5,1) (1,1)};
\end{axis}
\end{tikzpicture}

\section{TikZ data visualization}
% adapted from TikZ/PGF manual (v3.1.9a) section 84.4.2
\tikz \datavisualization [
    school book axes,
    visualize as line=1,
    visualize as line=2,
    visualize as line=3,
    style sheet=MyStyle]
data point [x=0, y=0, set=1]
data point [x=2, y=2, set=1]
data point [x=0, y=1, set=2]
data point [x=2, y=1, set=2]
data point [x=0.5, y=1.5, set=3]
data point [x=2.25, y=1.75, set=3];

\end{document}

output

What it does

In section (A) of the preamble, the two "input arguments" - the name of the colormap (\MyColorMapName) and a comma separated list of sample values in range [0,1] (\MyColorSamples) - are specified.

In section (B) of the preamble, a first loop over \MyColorSamples is executed. Afterwards, the number of values in the list is available by the counter MyColorSampleSize, an internal list (cf. etoolbox) is created (\MyColorSampleIDs), containing sample IDs (i.e. <1, 2, 3, ...>) and individual values can be accessed via the \MyColorSample{<id>} command.

In section (C) of the preamble, the sample values are mapped to range [0,1000] by means of a second loop. The resulting values are made available via the commands \MyColorMapSamples and \MyColorMapSample{<id>} respectively. Note that I was able to replace the Lua code by using the calculus package (part of calculator).

In section (D) of the preamble, another loop is executed to extract the actual xcolor colors from the colormap \MyColorMapName. The individual colors can be accessed via the command \MyColor{<id>}. Note that the "default color" needs to be restored, because plots will refer to this color for things like drawing axes.

In section (E) of the preamble, the pgfplots cycle list MyColorCycleList is defined as before.

In section (F) of the preamble, a TikZ/PGF style sheet MyStyle is defined by means of another loop. Note that execution of the loop needs to be nested inside an \edef for correct macro expansion.

You must log in to answer this question.

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