% \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> % % % \fi % \begin{macrocode} %%% File 'luaaddplot.tex', generated from luaaddplot.dtx'. %%% File 'luaaddplot.sty', generated from luaaddplot.dtx'. %-- File 'luaaddplot.lua', generated from luaaddplot.dtx'. %--[[ %% %% luaaddplot.dtx %% Copyright 2022 Reinhard Kotucha %% %% 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. %--]] % \end{macrocode} % \subsection{luaaddplot.tex} % \begin{macrocode} %<*tex> \directlua{require('luaaddplot')} \def\luaaddplot#1file#2;{ \directlua{luaaddplot.opts('#1')luaaddplot.readfile(#2)}} % % \end{macrocode} % \subsection{luaaddplot.sty} % \begin{macrocode} %<*sty> \ProvidesPackage{luaaddplot}[2022/03/18/ v1.0] \input luaaddplot.tex % % \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 % % \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: