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!

1
  • \pck_draw should be \pck_draw:.
    – Manuel
    Commented Feb 8, 2018 at 11:05

1 Answer 1

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}

You must log in to answer this question.

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