4

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

  • 1
    What is the merit of this awful syntax over plain \draw? – Henri Menke Sep 28 '17 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. – gaurav gupta Sep 28 '17 at 5:44
4

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

  • 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 '17 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 '17 at 4:34
2

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

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.