7

I am using \NewDocumentCommand from xparse for creating customized commands. The actual commands I am creating have a lot of parameters, so I am giving a simpler example here. I would like to have key-values (or named values) that apparently pgfkeys provides. I tried to read some document and play around with it (for about 2 hours now) without much success.

Current version (Working but not ideal):

\documentclass[11pt]{article}
\usepackage{xparse}
\usepackage{tikz}

\NewDocumentCommand \myline {O{0}O{0}O{0}O{0}}
{
    \draw [very thick, ->] (#1,#2) -- (#3,#4);
}

\begin{document}
\begin{tikzpicture}
\myline[7][5][][1] %uses default value (0) for #3
\end{tikzpicture}
\end{document}

Output:

Output

The problem is that when the number of parameters becomes large (10 or so), writing something like:

\diagram[arr][4][600][2][4][8][6][{1,7,2,9}]

is clearly a horrendous way of setting things up :(

What I would like instead is:

\documentclass[11pt]{article}
\usepackage{xparse}
\usepackage{tikz}

\NewDocumentCommand \myline {O{0}O{0}O{0}O{0}}
{
    \draw [very thick, ->] (#1,#2) -- (#3,#4);
}

\begin{document}
\begin{tikzpicture}

%--------- RELEVANT CHANGE -------
\myline[x1=7, y1=5, y2=1] %want to use default value for x2

\end{tikzpicture}
\end{document}

Call and output of actual code for anyone interested in understanding the scope of the problem:

\begin{tikzpicture}
\memory{data}{8}{320}{6}{4}{4}{8}{{12.5, 6.4, 8.5, 9.6, -3.4, -6.8, 0, -4.5}}
\end{tikzpicture}

Memory diagram

2
  • 1
    What is the merit of this awful syntax over plain \draw? Sep 28, 2017 at 5:42
  • as i said, this is just an example. in my actual code, i am drawing memory diagrams. i'll add a sample output from the actual code. Sep 28, 2017 at 5:44

2 Answers 2

7

Another option is to store the values inside the keys rather than in macros. I prefer this approach because the keys exist anyway so you might as well use them. This also makes it easy to set defaults -- and by calling \pgfkeys inside an environment you can make any key changes "local" to that environment.

You can access the key values using \pgfkeysvalueof, so when I am using key values a lot I define a "helper function" as a short cut for getting to the key values:

 \newcommand\MyVal[1]{\pgfkeysvalueof{/myline/#1}}

There's one catch, with either approach: you need to define the keys before you use them (there is also an .unknown handler for processing unknown keys, so it is possible to cater for "random" keys if you need to).

Here's the full code:

\documentclass[tikz, border=4mm]{standalone}

\usepackage{pgfkeys}
\usepackage{xparse}

\pgfkeys{/myline/.is family, /myline,
  x1/.initial=1,
  y1/.initial=1,
  x2/.initial=1,
  y2/.initial=1,
}
\newcommand\MyVal[1]{\pgfkeysvalueof{/myline/#1}}

\NewDocumentCommand\myline{m} {
  \begin{tikzpicture}
    \pgfqkeys{/myline}{#1}% keep key changes local
    \draw[very thick, ->] (\MyVal{x1},\MyVal{y1}) -- (\MyVal{x2},\MyVal{y2});
  \end{tikzpicture}
}

\begin{document}

  \myline{x1=0, y1=0, x2=2, y2=2}

\end{document}

This results in the same output:

enter image description here

2
  • 1
    and if you want the arguments to be mandatory you can use something like this approach (use \PackageError{\PackageName}{Mandatory key '\pgfkeyscurrentpath' not given}{#1}% instead of \Packagewarning).
    – jakun
    Nov 9, 2017 at 6:01
  • The key changes are local to groups also with macros. I find the use of \pgfleysvalueof excessively verbose. And you have to define your own macro anyway. But it’s a matter of taste I suppose :)
    – gigabytes
    Nov 11, 2017 at 4:34
4

Using pgfkeys is actually pretty simple. Keys are arranged into a tree, similar to directories, so the first thing to do is to choose the "home" directory for keys of your command, let's say /myline.

Then you set up the keys through the \pgfkeys command or, as in this case, the \pgfqkeys command (which differs only by letting you set a default path for all the keys set with it).

Keys are created by assigning them a 'handler', which specifies how the key value is interpreted. In the example below I chose to use the .store in handler, which assigns the value set to the keys to a given macro, but in the manual (section Utilities/Key Management/Key Handlers) you find quite a lot of handlers to implement all sorts of logic for you keys.

The keys setup can be done once for all and then, at each invocation of the command, another call to \pgfqkeys is used to set the keys using the user-provided argument. As you can see, you don't really need xparse here, a simple \newcommand would do the job.

\documentclass{standalone}

\usepackage{pgfkeys}
\usepackage{xparse}
\usepackage{tikz}

\pgfqkeys{/myline}{
  x1/.store in=\xone,
  y1/.store in=\yone,
  x2/.store in=\xtwo,
  y2/.store in=\ytwo
}

\NewDocumentCommand\myline{m} {
  \pgfqkeys{/myline}{#1}
  \begin{tikzpicture}
    \draw[very thick, ->] (\xone,\yone) -- (\xtwo,\ytwo);
  \end{tikzpicture}
}

\begin{document}

  \myline{x1=0, y1=0, x2=2, y2=2}

\end{document}

output

3
  • Couldn't l3keys also achieve what pgfkeys does in this example?
    – Erwann
    Jan 3, 2020 at 2:18
  • Yes, sure. I’m not familiar with it though. It would be interesting to see an answer based on it to compare the two approaches.
    – gigabytes
    Jan 3, 2020 at 8:14
  • here maybe: tex.stackexchange.com/questions/523083/…
    – Erwann
    Jan 5, 2020 at 22:12

You must log in to answer this question.

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