1

I've just started learning expl3 programming and trying to create a parser for drawing a type of TikZ/PGF plot. Basically I want

\begin{pck}
    plot node1 .3 .3;
    plot node2 .7 .7;
\end{pck}

to expand into

\begin{tikzpicture}
    \begin{axis}[xmin=0, xmax=1,
                 ymin=0, ymax=1]
        \node (node1) at (axis cs:.3, .3) [circle, draw] {};
        \node (node1) at (axis cs:.7, .7) [circle, draw] {};
    \end{axis}
\end{tikzpicture}

The text has in the environment has to be completely parsed first, before expanding it to the TikZ code as I want to do some processing of some of the arguments.

I have the following code so far.

\documentclass{article}

\usepackage[check-declarations]{expl3}
\usepackage{environ}
\usepackage{pgfplots}
\pgfplotsset{compat=1.15}

\ExplSyntaxOn

\tl_new:N \pck_objects_tl

\seq_new:N \pck_labels
\seq_new:N \pck_xs
\seq_new:N \pck_ys
\seq_new:N \pck_edgs_left
\seq_new:N \pck_edgs_right

\tl_new:N \pck_label
\tl_new:N \pck_x
\tl_new:N \pck_y
\tl_new:N \pck_edg_left
\tl_new:N \pck_edg_right

\cs_new:Npn \pck_draw {
    \bool_do_until:nn {\seq_if_empty_p:N \pck_labels} {
        \seq_pop_left:NN \pck_labels \pck_label
        \seq_pop_left:NN \pck_xs \pck_x
        \seq_pop_left:NN \pck_ys \pck_y 

        \node~(\pck_label)~at~(axis~cs\c_colon_str~\pck_x,~\pck_y)~[circle, draw]~\bgroup \egroup ; \par
    }
}

\NewEnviron{pck}[1][] {
    \pck_parse:V \BODY

    \begin{tikzpicture}
        \begin{axis}[xmin=0, xmax=1,
                     ymin=0, ymax=1]
            \pck_draw
        \end{axis}
    \end{tikzpicture}\par
}

\cs_new_protected:Npn \pck_parse:n #1{
    \tl_set:Nn \pck_objects_tl{#1}
    \tl_remove_all:Nn \pck_objects_tl{\par}
    \tl_replace_all:Nnn \pck_objects_tl{plot~}{\pck_parse_plot:w}
    \tl_use:N \pck_objects_tl 
}

\cs_generate_variant:Nn \pck_parse:n {V}

\cs_new_protected:Npn \pck_parse_plot:w #1 ~ #2 ~ #3 ; {
    \seq_put_right:Nn \pck_labels {#1}
    \seq_put_right:Nn \pck_xs {#2}
    \seq_put_right:Nn \pck_ys {#3}
}

\ExplSyntaxOff

\begin{document}
    \begin{pck}
        plot node1 .3 .3;
        plot node2 .7 .7;
    \end{pck}
\end{document}

However, this code draws all of the nodes on top of each other. I believe it is because when the sequences, eg. \pck_labels, are popped to the token list \pck_label, the token list is not expanded into node1 or node2 immediately, but the expansions happen last so the all expand to node2 etc. I really can not figure out how to expand the tokens the correct way, I have tried with with generating variants with the f and x spesifications and using \exp_after and \use. Any suggestions?

Also, since I am completely new to expl3, I am very happy to receive any feedback on the code in general!

  • \pck_draw should be \pck_draw:. – Manuel Feb 8 '18 at 11:05
1

This code will solve your problems. I do not use more than one sequence. By doing some x-type expansion it will plot your points. Please note that you should add suffixes containing the data type in l3 names.

plot

\documentclass{article}

\usepackage[check-declarations]{expl3}
\usepackage{environ}
\usepackage{pgfplots}
\pgfplotsset{compat=1.15}

\ExplSyntaxOn

\tl_new:N \pck_objects_tl
\seq_new:N \pck_plot_seq

\cs_new:Npn \pck_node:nnn #1#2#3 {
    \node~(#1)~at~(axis~cs\c_colon_str#2,#3)~[circle, draw] { };
}
\cs_generate_variant:Nn \pck_node:nnn {xxx}


\cs_new:Npn \pck_draw {
    \seq_map_inline:Nn \pck_plot_seq
        {
            \clist_set:Nn \l_tmpa_clist { ##1 }
            \pck_node:xxx { \clist_item:Nn \l_tmpa_clist { 1 } }
                { \clist_item:Nn \l_tmpa_clist { 2 } }
                { \clist_item:Nn \l_tmpa_clist { 3 } }
        }
}

\NewEnviron{pck}[1][] {
    \pck_parse:V \BODY
    \begin{tikzpicture}
        \begin{axis}[xmin=0, xmax=1,
                     ymin=0, ymax=1]
            \pck_draw
        \end{axis}
    \end{tikzpicture}\par
}

\cs_new_protected:Npn \pck_parse:n #1{
    \tl_set:Nn \pck_objects_tl{#1}
    \tl_remove_all:Nn \pck_objects_tl{\par}
    \tl_replace_all:Nnn \pck_objects_tl{plot~}{\pck_parse_plot:w}
    \tl_use:N \pck_objects_tl 
}

\cs_generate_variant:Nn \pck_parse:n { V }

\cs_new_protected:Npn \pck_parse_plot:w #1 ~ #2 ~ #3 ; {
    \seq_put_right:Nn \pck_plot_seq {#1,#2,#3}
}

\ExplSyntaxOff

\begin{document}
    \begin{pck}
        plot node1 .3 .3;
        plot node2 .7 .7;
        plot node3 .5 .5;
    \end{pck}
\end{document}

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.