summaryrefslogtreecommitdiff
path: root/macros/luatex/generic/luaaddplot/luaaddplot.dtx
blob: 7d3e4bf8c2489c5f9401b7e3f0c3a3fb39234062 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
% \iffalse meta-comment
%
% $Id: luaaddplot.dtx 3 2022-03-19 23:12:51Z reinhard $
%
%<*driver> 
\documentclass[a4paper,11pt]{ltxdoc}
\MakeShortVerb{\|}

\advance\textheight by 2\baselineskip 
\usepackage[english]{babel}
\usepackage{tgpagella}
\usepackage[dvipsnames]{xcolor}
\usepackage{parskip}
\usepackage{siunitx}
\usepackage[colorlinks,bookmarksopen,bookmarksnumbered]{hyperref}
\hypersetup{linkcolor=BrickRed}
 
\author{Reinhard Kotucha}
\title{\textsf{luaaddplot}}
\begin{document}
\maketitle
\vspace*{1cm}

\begin{abstract}
  \parindent=0pt \parskip=1ex
  \noindent The \textsf{pgfplots} package supports plotting data from files.
  If these files are generated by measuring devices they almost always
  have to be pre-processed.
  
  This packge provides a macro |\luaaddplot| which extends the
  functionality of |\addplot| by an optional argument containing
  a $\lambda$- expression which is evaluated for each line of the data
  file.

  The package requires Lua\TeX\ or Lua\LaTeX.
\end{abstract}
\vspace*{1cm}
\tableofcontents
\vspace*{\fill}

\newpage

\section{Introduction}
When plotting files generated by measuring devices the data files
often have to be pre-processed before they can be passed to \textsf{pgfplots}.  
In most cases a header describing the device configuration must be
removed, column delimiters have to be changed, and units have to be
scaled (\si{\hertz} to \si{\mega\hertz}, \si{\volt} to
\si{\micro\volt}, etc\ldots).  In some cases more complex operations
are required.

\subsection{Usage}

\verb|  \luaaddplot|\oarg{options}| file "|%
$\langle$\textit{filename}$\rangle$|"|[|, |$\langle$\textit{$\lambda$-expression}$\rangle$]|;|

Everything between \cs{luaaddplot} and the keyword |file| is passed to
\cs{addplot}, everything between |file| and the semicolon is
processed by Lua and valid Lua syntax is required here.  You can
consider code between |file| and the terminating semicolon as
arguments of a Lua function with braces omitted. 

\subsection{Reading the data file}

Data files generated by measuring devices usually have an ASCII
header describing the settings. These lines are often preceded by
comment characters but not always.  In order to avoid pre-processing
with another tool, all lines which do not begin with a number are
ignored.

Different devices use different column delimiters.  Therefore tabs,
colons, semicolons, and commas are replaced by a space.  With other
words, various datafile formats are converted to a format specified by
\textsc{Matlab}.

\subsection{\texorpdfstring{$\lambda$}{lambda}-Expressions}

A $\lambda$-expression is an anonymous function and looks like this: 
\begin{verbatim}
  function (a) 
    return a[1], a[2] 
  end
\end{verbatim}

The formal parameter |a| (its name can be chosen arbitrarily) is
replaced by an ordered list of columns for each line in the data file.
The return values are the $x$ and $y$ values to be plotted and are
passed to \cs{addplot}.  Always two values must be returned.  Please
note that the index of the first column is 1 in Lua and not 0, as in
many other programming languages.

In the example above the first and second column of the data file
will be plotted.  This is the default if the $\lambda$-expression is
omitted. 

\newpage

\section{Examples}

\subsection{Scaling}

The following is an excerpt of a data file generated by a spectrum analyzer.

\begin{verbatim}
x-Unit;Hz;
y-Unit;dBm;
Preamplifier;OFF;
Transducer;OFF;
Values;501;
0;43.660163879394531;
6000000;-53.616184234619141;
12000000;-60.31707763671875;
18000000;-62.548038482666016;
54000000;-66.722061157226563;
\end{verbatim}

Frequencies are in \si{\hertz} but for the plot we prefer
\si{\mega\hertz}.  The solution is
\begin{verbatim}
\luaaddplot[blue] file "spectrum.data", function (col) 
                                          return col[1]/1e6, col2
                                        end;
\end{verbatim}


\subsection{Processing}

The following is an excerpt of a data file generated by a vector
network analyzer.

\begin{verbatim}
%% Date: 2021-02-25 11:36:04
%% Data & Calibration Information:
%% Trc1:S11(Full One Port)
%%freq[Hz] re:Trc1_S11 im:Trc1_S11 
6.650000000000000E+008,3.684957681171731E-001,-9.205383204111828E-001,
6.652500000000000E+008,3.717039523633851E-001,-9.215835251874305E-001,
6.655000000000000E+008,3.687706454916999E-001,-9.207422307051146E-001,
6.657500000000000E+008,3.574212650433284E-001,-9.176705980253278E-001,
6.660000000000000E+008,3.453552411257967E-001,-9.254690887689956E-001,
\end{verbatim}

The first column denotes the frequency in \si{\hertz}, the second and
third column denote the real and imaginary part of the impedance
$s_{11}$ respectively.

Now we want to plot
\begin{displaymath}
  20 \log_{10} \sqrt{(\text{Re\,} s_{11})^2 + (\text{Im\,} s_{11})^2} 
\end{displaymath}
with frequencies in \si{\mega\hertz}. 

The solution is
\begin{verbatim}
\luaaddplot[green] file "s11.data",
        function (col) 
           return col[1]/1e6, 20*math.log10(math.sqrt(col[2]^2 + col[3]^2))
        end;
\end{verbatim}


\newpage
\section{Implementation} 
\DocInput{luaaddplot.dtx}
\end{document}
%<*tex|sty|lua>
%</tex|sty|lua>

%</driver> 
% \fi
%    \begin{macrocode}
%<tex>%% File 'luaaddplot.tex', generated from luaaddplot.dtx'.
%<sty>%% File 'luaaddplot.sty', generated from luaaddplot.dtx'.
%<lua>-- File 'luaaddplot.lua', generated from luaaddplot.dtx'.
%<lua>--[[
%%
%% luaaddplot.dtx
%% Copyright 2022 Reinhard Kotucha <reinhard.kotucha@gmx.net>
%%
%% This work may be distributed and/or modified under the
%% conditions of the LaTeX Project Public License, either version 1.3
%% of this license or (at your option) any later version.
%% The latest version of this license is in
%%   http://www.latex-project.org/lppl.txt
%% and version 1.3 or later is part of all distributions of LaTeX
%% version 2005/12/01 or later.
%%
%% This work has the LPPL maintenance status `maintained'.
%% 
%% The Current Maintainer of this work is Reinhard Kotucha.
%%
%% This work consists of the files luaaddplot.dtx and luaaddplot.ins
%% and the derived files luaaddplot.tex, luaaddplot.sty, and luaaddplot.lua.
%<lua>--]]
%    \end{macrocode}
% \subsection{luaaddplot.tex}
%    \begin{macrocode}
%<*tex>
\directlua{require('luaaddplot')}
\def\luaaddplot#1file#2;{
        \directlua{luaaddplot.opts('#1')luaaddplot.readfile(#2)}}
%</tex> 
%    \end{macrocode}
% \subsection{luaaddplot.sty}
%    \begin{macrocode}
%<*sty> \ProvidesPackage{luaaddplot}[2022/03/18/ v1.0]
\input luaaddplot.tex
%</sty>
%    \end{macrocode}
% \subsection{luaaddplot.lua}
%    \begin{macrocode}
%<*lua>

module('luaaddplot', package.seeall)

%    \end{macrocode}
% \DescribeMacro{readfile()}
% Read and pre-process file \verb|file| and apply
% $\lambda$-expression.  If the second argument is \verb|nil| the
% first and second column is returned. 
%    \begin{macrocode}
function readfile (file, lambda)
%    \end{macrocode}
% Check whether datafile exists.
%    \begin{macrocode}
  if not lfs.isfile(file) then
    error('\nERROR: File "'..file..'" not found.')
  end

  local data = io.open(file)

  for line in data:lines() do
%    \end{macrocode}
% Remove all spaces at the beginning of a line.
%    \begin{macrocode}
    line = line:gsub('^%s+', '')
%    \end{macrocode}
% Ignore all lines which don't begin with a number.  All comments
% and empty lines in data files are ignored.
%    \begin{macrocode}
    if line:match('^%-?%.?[0-9]') then
%    \end{macrocode}
% Replace possible non-space delimiters by spaces.  This allows to
% process various datafile formats the same way as \textsc{Matlab}
% files without manual interaction.
%    \begin{macrocode}
      line = line:gsub('[\t:;,]', ' ')
%    \end{macrocode}
% The result must be a table with two columns.  If no $\lambda$
% expression is provided, the first two colums of the data file are
% returned.  With a $\lambda$ expression as second argument arbitrary
% columns can be selected from a data file and can be pre-processed in
% any way possible.
%    \begin{macrocode}
      local a, b
      local cols = line:explode (' +')
%    \end{macrocode}
% Convert strings to numbers.  Because $\lambda$ expressions can
% access any column we convert all table entries from strings
% to numbers, if possible, instead of only the return values.
% Numbers are returned to \TeX\ as floating point numbers.
%    \begin{macrocode}
      for i, col in ipairs(cols) do
        cols[i] = tonumber(cols[i])
      end

      if lambda then
        a, b = lambda(cols)
        if a and b then
          tex.print(string.format('%g %g', a, b))
        end
      else
        tex.print(string.format('%g %g', cols[1], cols[2]))
      end
    end
  end
  tex.print('};')
  data:close()
end
%    \end{macrocode}
% \DescribeMacro{opts()}
% Pass optional arguments from \verb|\luaaddplot| to \verb|\addplot|.
%    \begin{macrocode}

function opts (s)
  tex.print('\\addplot'..s..' table {')
end

% </lua>
%    \end{macrocode}

%\endinput
% Local Variables:
%  mode: LaTeX
%  TeX-master: t
%  TeX-engine: luatex
%  indent-tabs-mode: nil
%  coding: utf-8-unix
% End:
% vim:set tabstop=2 expandtab: