%D \module %D [ file=t-gnuplot.mkiv, %D version=2013.05.09, %D title=\CONTEXT\ Extra Modules, %D subtitle=\GNUPLOT\ Inclusion, %D author={Mojca Miklavec, Marco Patzer, Hans Hagen, Taco Hoekwater, Aditya Mahajan}, %D date=\currentdate, %D copyright=\PRAGMA] % begin info % % title : Gnuplot module % % comment : simplifies inclusion of gnuplot-generated graphs into ConTeXt documents % status : stable, supports both MKII and MKIV % % end info %D This module is used for creating gnuplot graphs on-the-fly and including them %D into documents. %D %D Known Bugs: %D %D \startitemize %D \item spurious space \& page %D \stopitemize %D %D TODO (Optimisations): %D %D \startitemize %D \item optimize the number of gnuplot runs (if possible, gnuplot should be run only once) %D \item optimize the number of times for loading/converting an already used graphic %D \item pstopdf is a bit slow %D \stopitemize %D %D TODO (Handle things that may go wrong): %D - gnuplot executable doesn't exist %D - context terminal isn't available or some other failure in gnuplot script (no file created) %D - write18 disabled (you may call gnuplot later - create a script) %D %D TODO (Missing functionality): %D %D - a lot ... \writestatus{loading}{Gnuplot module} \startmodule[gnuplot] \unprotect \def\c!terminal {terminal} \def\c!options {options} \def\c!pointset {pointset} \def\c!purge {purge} %D MPextensions %D %D XXX %D if possible, they should be specific to \type{\startGNUPLOTgraphic}, %D so unvisible to \type{MPcode} %D (probably something like \type+\appendtoks ... to\everyGNUPLOTgraphic+) \startMPinitializations % load metapost macros (only once) input mp-gnuplot.mp ; % number of points defined with \setupGNUPLOTterminal[pointset=...] %gp_num_points_with_tex := \gp:num:pointswithtex; gp_num_points_with_tex := 3; % main color should be set equal to the current text color gp_color_foreground := \MPcolor{currentcolor}; gp_color_lt[-2] := gp_color_foreground; % TODO: is there any chance to make this local to gnuplot? % linejoin & linecap linejoin := \@@GNUPLOT@term@context@linejoin; % linecap := \gp:term:context:linecap; % dashes or solid? (true/false) gp_use_dashed := \@@GNUPLOT@term@context@is@dashed; % dashlength scale % gp_scale_dashlength := \gp:term:context:dashlength; % linewidth scale gp_scale_linewidth := \@@GNUPLOT@term@context@linewidth; gp_scale_text := \@@GNUPLOT@term@context@fontscale; % linejoin := \gp:term:context:linejoin; % linecap := \gp:term:context:linecap; % % dashes or solid? (true/false) % gp_use_dashed := \gp:term:context:dashed; % % dashlength scale % gp_scale_dashlength := \gp:term:context:dashlength; % % linewidth scale % gp_scale_linewidth := \gp:term:context:linewidth; gp_points_with := gp_points_with_\@@GNUPLOT@term@context@points; \stopMPinitializations %D We need a \type{\strut} in front of labels for better vertical centering. %D This might still fail for Zapfino and alike where \type{\strut} might be smaller %D than the actual font height. %D %D TODO (optional improvement): instead of placing \type{\strut} in front, %D create a \type{\hbox} and adjust it's dimensions to \type{\strut}'s height and depth. %D Aditya, thanks a lot for requesting it! %D Hans, thanks a lot for implementing this! \definetextext[gp]{\strut} %D TODO (feature request): %D \starttyping %D \sometxt[gp][ss,20pt]{abc} %D \stoptyping %D should become equivalent to %D \starttyping %D \sometxt{\switchtobodyfont[ss,20pt]\strut abc} %D \stoptyping %D %D Or, even more drastic perhaps, I would love to implement %D \starttyping %D \sometxt[gp][iwona,bold,c]{abc} %D \stoptyping %D meaning: iwona, bold typeface, size \quote{c} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % TODO: make \sometxt[gp][12pt]{text} work in MKIV %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \newcounter\GNUPLOTnumber \newdimen\GNUPLOThcharsize \newdimen\GNUPLOTvcharsize \newcounter\tikzGNUPLOTnumber % macro to calculate true character size from current font % (However it is not 100 % that it gets the job properly done % in case that other font settings are used inside the picture.) \def\calculateGNUPLOTcharsize{% \global\GNUPLOThcharsize=1.05\fontcharwd\font`0% \global\GNUPLOTvcharsize=1.05\fontcharht\font`0% \global\advance\GNUPLOTvcharsize by 1.05\fontchardp\font`g% } %D \macros %D {startGNUPLOTinclusions, resetGNUPLOTinclusions} %D %D For those who want to have two or more graphs with similar options, %D these options may be included inside \type{\startMPinclusions ... \stopMPinclusions} %D and will be place on the top of the created \GNUPLOT\ script. %D %D \starttyping %D \startGNUPLOTinclusions %D set xlabel '$x$' %D set ylabel '$y$' %D set format y "%.1f" %D \stopGNUPLOTinclusions %D %D \startGNUPLOTscript[sin] %D plot sin(x) %D \stopGNUPLOTscript %D \startGNUPLOTscript[cos] %D plot cos(x) %D \stopGNUPLOTscript %D \stoptyping \long\def\startGNUPLOTinclusions {\def\stopGNUPLOTinclusions{\ifx\savebuffer\undefined \else \savebuffer[gnuplot-inclusions]\fi}% \dostartbuffer[gnuplot-inclusions][startGNUPLOTinclusions][stopGNUPLOTinclusions]} % \def\resetGNUPLOTinclusions{\let\GNUPLOTinclusions\empty} % creates an empty file (there must be a cleaner way to do it) \def\resetGNUPLOTinclusions {\immediate\openout\scratchwrite=\jobname-gnuplot-inclusions.tmp \immediate\closeout\scratchwrite} %\startbuffer[gnuplot-inclusions]\stopbuffer\ifx\savebuffer\undefined \else \savebuffer[gnuplot-inclusions]\fi} \resetGNUPLOTinclusions %D On the other hand, one can probably achieve the same effect %D when drawing two plots inside the same script, like that: %D %D \starttyping %D \startGNUPLOTscript[sin and cos] %D set xlabel '$x$' %D set ylabel '$y$' %D set format y "%.1f" %D plot sin(x) %D plot cos(x) %D \stopGNUPLOTscript %D \stoptyping %D %D and then recall the graphics using \type{\useGNUPLOTgraphic[sin and cos][1]}. %D \macros %D {startGNUPLOTscript} %D %D \starttyping %D \startGNUPLOTscript{some name} %D plot sin(x) %D \stopGNUPLOTscript %D \stoptyping \def\startGNUPLOTscript {\bgroup\dosingleempty\dostartGNUPLOTscript} % \def\redostartGNUPLOTscript#1 % {\obeylines % \catcode`\%=\@@letter % \catcode`\|=\@@letter % \catcode`\$=\@@letter % \dodostartGNUPLOTscript{#1}% % %\dostartGNUPLOTscript[#2] % } % % \def\dostartGNUPLOTscript[#1]% % {\iffirstargument % \obeylines % \catcode`\%=\@@letter % \catcode`\|=\@@letter % \catcode`\$=\@@letter % \dodostartGNUPLOTscript{#1}% % \else % \redostartGNUPLOTscript % \fi % } \def\dostartGNUPLOTscript[#1]% {%\iffirstargument \dodostartGNUPLOTscript{#1}% %\else % \dodostartGNUPLOTscript %\fi } % gps:n:{name} = gnuplotscript : number : {name} - number of script with name {name} \long\def\dodostartGNUPLOTscript#1%#2\stopGNUPLOTscript {\doglobal\increment\GNUPLOTnumber \letgvalue{gps:n:#1}\GNUPLOTnumber % in case of LuaTeX we need to write the buffer into file explicitely \def\stopGNUPLOTscript{\egroup \ifx\savebuffer\undefined \else \savebuffer[gnuplot-\GNUPLOTnumber]\fi}% \dostartbuffer[gnuplot-\GNUPLOTnumber][startGNUPLOTscript][stopGNUPLOTscript]% } % When are the graphics processed/read? % % - \gps:n:{name} (gnuplot script:name:{name}) holds the number of gnuplot script; % - that number was defined if we created the plot using \startGNUPLOTscript{name} % - and most probably undefined if we only issued \processGNUPLOTfile[name][filename] % => if, at the time of issuing \processGNUPLOTfile[name][filename], \gps:n:{name} is not defined, % it should be defined at that time % - \gpe:{name}:{terminal} (gnuplot graphic executed:{name}:{terminal}) % is defined if we executed the command for that specific name and for that terminal % (once it will probably be 0 for a failed run and 1 for a successful one) % \useGNUPLOTgraphic[name] has three different ways of working: % - it can be called after \processGNUPLOTfile[name][filename] % which defined MP graphics that are now used % - it can be called for the first time under the current terminal % in that case it compiles the graphic and includes it % - it can be called for the second, third, ... time % in which case it only includes files without compiling it %D \macros %D {useGNUPLOTgraphic} % 5 ways of calling it: % - \useGNUPLOTgraphic{name} % - \useGNUPLOTgraphic[name] % - \useGNUPLOTgraphic[name][1,2,5] % - \useGNUPLOTgraphic[name][width=.8\textwidth] % - \useGNUPLOTgraphic[name][1,2,5][width=.8\textwidth] % this code takes care of reading arguments \def\useGNUPLOTgraphic {\dotripleempty\douseGNUPLOTgraphic} \def\douseGNUPLOTgraphic[#1][#2][#3]% {\doifelse{#3}{}{% % < 3 arguments \doifelse{#2}{}% % 1 argument % as in \useGNUPLOTgraphic[name] {\dodouseGNUPLOTgraphic[#1][][]}% % % as in \useGNUPLOTgraphic{name} % {\redouseGNUPLOTgraphic[][][]}% % 2 arguments {\doifassignmentelse{#2}% % as in \useGNUPLOTgraphic[name][width=.8\textwidth] {\dodouseGNUPLOTgraphic[#1][][#2]}% % as in \useGNUPLOTgraphic[name][1,2,5] {\dodouseGNUPLOTgraphic[#1][#2][]}% }% }% % as in \useGNUPLOTgraphic[name][1,2,5][width=.8\textwidth] {\dodouseGNUPLOTgraphic[#1][#2][#3]}% } \def\redouseGNUPLOTgraphic[#1][#2][#3]#4% {\dodouseGNUPLOTgraphic[#4][][]} % and this code actually does something with it %D \doifundefined {string} {...} %D \doifdefined {string} {...} %D \doifundefinedelse {string} {then ...} {else ...} %D \doifdefinedelse {string} {then ...} {else ...} % \doifGNUPLOTscriptdefined{name}{...} % if gnuplot script with {name} and current terminal has already been processed % \doifGNUPLOTscriptprocessed{name}{...} % \letGNUPLOTscriptprocessed[optional terminal]{name} signals that the gnuplot script named {name} % has already been processed with the current terminal % TODO: currently it is always defined to be one as soon as one tries to process it, % even if en error is produced; in future it would be helpful if it would be set to zero % if it was unsuccessfully executed; % that is needed, since scripts are processed only when one first asks for including the graphic \def\letGNUPLOTscriptprocessed {\dosingleempty\doletGNUPLOTscriptprocessed} %\def\doletGNUPLOTscriptprocessed[#1]#2% %{\letgvalue{gpe:#1:\@@GNUPLOTterminal}\plusone} \def\doletGNUPLOTscriptprocessed[#1]#2% {\iffirstargument % terminal has been specified \letgvalue{gpe:#2:#1}\plusone \else % no terminal specified - use the current one \letgvalue{gpe:#2:\@@GNUPLOTterminal}\plusone \fi} % Although that should preferably not happen, one might come to an idea of defining % a gnuplot script with the same name as already defined. % In that case the old script cannot be referenced any more, but we can still try % to do out best to make it work anyway. We have to do two things: % - claim that script with that name hasn't been defined yet, so that processing will happen again % (TODO: do it in a more elegant way for all known terminals) % - undefine any metapost graphics (TODO: I have no idea yet how it can be done) % % \resetGNUPLOTscriptprocessed{name} \def\resetGNUPLOTscriptprocessed#1% {\bgroup % claim that the script with {name} (#1) hasn't been processed with {terminal} (##1) yet \def\undefineGNUPLOTscriptforterminal##1{\letbeundefined{gpe:#1:##1}}% % TODO: the list of available terminals should be generated automatically \processcommalist[context,postscript,ps,eps,pdf,metapost,mp,png]\undefineGNUPLOTscriptforterminal \resetGNUPLOTgraphics{#1}% \egroup} % \resetGNUPLOTgraphics{name} undefines any gnuplot graphic defined with \startGNUPLOTgraphic[name][number] \def\resetGNUPLOTgraphics#1% {\doloop {\doifMPgraphicelse{gpg:#1:\recurselevel}% % TODO: be aware - @@MPG is low-level ConTeXt variable which might change without notice, % it would be better to call this \undefineMPgraphic{gpg:#1:\recurselevel} or something similar {\letbeundefined{@@MPGgpg:#1:\recurselevel}}% {\exitloop}}% \doloop {\doifdefinedelse{TKZp:#1:\recurselevel}% {\letbeundefined{TKZp:#1:\recurselevel}}% {\exitloop}}% }% % TODO: this can probably be done in a better way \def\doifGNUPLOTscriptprocessed#1#2% {\doifdefined {gpe:#1:\@@GNUPLOTterminal}{#2}} \def\doifGNUPLOTscriptprocessedelse#1#2#3% {\doifdefinedelse {gpe:#1:\@@GNUPLOTterminal}{#2}{#3}} \def\doifGNUPLOTscriptnotprocessed#1#2% {\doifundefined {gpe:#1:\@@GNUPLOTterminal}{#2}} \def\doifGNUPLOTscriptnotprocessedelse#1#2#3% {\doifundefinedelse{gpe:#1:\@@GNUPLOTterminal}{#2}{#3}} % private % \writeandprocessGNUPLOTscript{name} \def\writeandprocessGNUPLOTscript#1% % TODO: if gps:n:#1 (holding the script content) is not defined, % error or warning should be issued % % only process the script if it has been defined and not processed before for the current terminal {\doifdefined{gps:n:#1}{\doifGNUPLOTscriptnotprocessed{#1}{% % \gpe:{name}:{terminal} is defined %\setgvalue{gpe:#1:\@@GNUPLOTterminal}{#2} \letGNUPLOTscriptprocessed{#1}% % call to gnuplot and processing/converting the graphics is only needed in the first ConTeXt run \doifmode{*\v!first}{% (perhaps also: if files haven't changed) \bgroup % for TikZ we want to calculate character size, so that it gets printed % to inclusions with \@@GNUPLOToptions \calculateGNUPLOTcharsize % catcodes trickery & alike %\the\everyGNUPLOTscript % open file for writing \immediate\openout\scratchwrite=\GNUPLOTfile.plt % TODO: terminal-specific options (default or provided by the user) \immediate\write\scratchwrite{\letterhash\space Do not modify this file - all changes will be overwritten}% \immediate\write\scratchwrite{\letterhash\space Change \jobname.tex instead.}% \immediate\write\scratchwrite{set terminal \@@GNUPLOToutput\space\@@GNUPLOToptions}% % add common inclusions in scripts for multiple similar plots %\doifnotempty % {\GNUPLOTinclusions}{\immediate\write\scratchwrite{\GNUPLOTinclusions}}% % include common gnuplot 'inclusions' \immediate\write\scratchwrite{load '\jobname-gnuplot-inclusions.tmp'}% % output file \immediate\write\scratchwrite{set output "\@@GNUPLOTresult"}% % write main contents of the script, like "plot sin(x)" %\immediate\write\scratchwrite{\getvalue{gps:d:\GNUPLOTnumber}}% \immediate\write\scratchwrite{load '\GNUPLOTfile.tmp'}% \immediate\closeout\scratchwrite \egroup % TODO: % - check the state of write18 and warn the user if it's disabled, % otherwise just everyone will start complaining that the module doens't work % - check if execution was successful; possible pitfalls: % - gnuplot doesn't exist as a binary % - gnuplot doesn't support context terminal % or some other error in script which results in empty output file % % run gnuplot & execute the script that has just been written % \executesystemcommand{mtxrun --ifchanged=\GNUPLOTfile.plt\space % --direct \@@GNUPLOTprogram\space\GNUPLOTfile.plt}% \executesystemcommand{mtxrun --direct \@@GNUPLOTprogram\space\GNUPLOTfile.plt}% \writestatus{aaa}{mtxrun --direct \@@GNUPLOTprogram\space\GNUPLOTfile.plt}% \convertGNUPLOTgraphic }% % for ConTeXt terminal only - read the result \doif{\@@GNUPLOTterminal}{context}{\processGNUPLOTfile[#1][\@@GNUPLOTresult]}% \doif{\@@GNUPLOTterminal}{tikz} {\processGNUPLOTfile[#1][\@@GNUPLOTresult]}% }}} % \dodouseGNUPLOTgraphic[name][numbers][options] \def\dodouseGNUPLOTgraphic[#1][#2][#3]% {\bgroup \doifdefinedelse{gps:n:#1} {\edef\GNUPLOTnumber{\getvalue{gps:n:#1}}% \edef\GNUPLOTfile {\jobname-gnuplot-\GNUPLOTnumber}% \writeandprocessGNUPLOTscript{#1}% % "ctxtools --purge" should delete the gnuplot script and other intermediate files % (but it seems that they are deleted automatically already; preferred or not?) % \registertempfile{\GNUPLOTfile.plt} % \registertempfile{\@@GNUPLOTresult} % \registertempfile{\@@GNUPLOTfinalresult} \doifelse{\@@GNUPLOTterminal}{context}% % for ConTeXt terminal only {\doifelse{#2}{}% % if no explicit figure number was specified, include all the figures {\doloop {\doifMPgraphicelse{gpg:#1:\recurselevel}% {\scale[#3]{\reuseMPgraphic{gpg:#1:\recurselevel}}}% {\exitloop}}}% % if numbers were specified, include the figures specified in the list only {\begingroup \def\useGNUPLOTgraphicN##1{\doifMPgraphicelse {gpg:#1:##1}% {\scale[#3]{\reuseMPgraphic{gpg:#1:##1}}}% % if graphic doesn't exist: draw a dummy frame instead and warn the user {\scale[#3]{\framed[frame=on,width=5in,height=3in,align={middle,lohi}]{GNUPLOT graphic #1, Nr. ##1 doesn't exist}}}}% \processcommalist[#2]\useGNUPLOTgraphicN \endgroup }% }{% % for TikZ terminal only \doifelse{\@@GNUPLOTterminal}{tikz}% {\doifelse{#2}{}% % if no explicit figure number was specified, include all the figures {\doloop {\doifdefinedelse{TKZp:#1:\recurselevel}% {\scale[#3]{\getvalue{TKZp:#1:\recurselevel}}}% {\exitloop}}}% % if numbers were specified, include the figures specified in the list only {\begingroup \def\useGNUPLOTgraphicN##1{\doifdefinedelse {TKZp:#1:##1}% {\scale[#3]{\getvalue{TKZp:#1:##1}}}% % if graphic doesn't exist: draw a dummy frame instead and warn the user {\scale[#3]{\framed[frame=on,width=5in,height=3in,align={middle,lohi}]{GNUPLOT graphic #1, Nr. ##1 doesn't exist}}}}% \processcommalist[#2]\useGNUPLOTgraphicN \endgroup }% }% % for all the other terminals % TODO: add more safety switches (if pages don't exist for example) {\doifelse{#2}{}% % if no explicite figure number was specified, include all the pages % TODO: properly handle METAPOST & PNG (only works for (E)PS & PDF) !!! {\getfiguredimensions[\@@GNUPLOTfinalresult]% \dorecurse{\noffigurepages}{\externalfigure[\@@GNUPLOTfinalresult][page=\recurselevel,#3]}}% % if numbers were specified, include the pages specified in the list only {\begingroup \def\useGNUPLOTgraphicN##1{\externalfigure[\@@GNUPLOTfinalresult][page=##1,#3]}% \processcommalist[#2]\useGNUPLOTgraphicN \endgroup }% }}% }% % else part - in case that graphic gets included with \processGNUPLOTfile[name][file] {\doifelse{\@@GNUPLOTterminal}{context} % TODO: this part has been literally copied from above; create a subroutine instead {\doifelse{#2}{}% % if no explicit figure number was specified, include all the figures {\doloop {\doifMPgraphicelse{gpg:#1:\recurselevel}% {\scale[#3]{\reuseMPgraphic{gpg:#1:\recurselevel}}}% {\exitloop}}}% % if numbers were specified, include the figures specified in the list only {\begingroup \def\useGNUPLOTgraphicN##1{\doifMPgraphicelse {gpg:#1:##1}% {\scale[#3]{\reuseMPgraphic{gpg:#1:##1}}}% % if graphic doesn't exist: draw a dummy frame instead and warn the user {\scale[#3]{\framed[frame=on,width=5in,height=3in,align={middle,lohi}]{GNUPLOT graphic #1, Nr. ##1 doesn't exist}}}}% \processcommalist[#2]\useGNUPLOTgraphicN \endgroup }% }% {\message{The gnuplot graphic #1 has not been defined.}}}% \egroup} %D \macros %D {setupGNUPLOT} \def\setupGNUPLOT % {\dodoubleempty\getparameters[@@GNUPLOT]} {\dosingleargument\dosetupGNUPLOT} \def\dosetupGNUPLOT[#1]% {\getparameters[@@GNUPLOT][#1]% % define all the necessary points according to the option "pointset" % % XXX: no idea why this is needed, but otherwise it complains that @@GNUPLOTpointset is undefined \edef\currentGNUPLOTpointset{\@@GNUPLOTpointset}% % \gp:num:pointswithtex is passed to metapost, so that it knows % how many points are defined and chooses the proper point % form a set of the defined ones % % for safety reasons define \gp:num:pointswithtex to be equal to 1 (it can only increase later), otherwise: % - (something mod 0) won't work % - if conversion is not defined, the number will retain its old value (not desirable) \edef\gp:num:pointswithtex{1}% \doloop{\doifelseconversionnumber{\@@GNUPLOTpointset}{\recurselevel}% {\edef\gp:num:pointswithtex{\recurselevel}}% {\exitloop}}% % in case of TikZ terminal we have to generate the needed style files first \doif{\@@GNUPLOTterminal}{tikz} {\executesystemcommand{gnuplot -e "set term tikz context createstyle"}\usemodule[gnuplot-lua-tikz]} % TODO: % - issue a warning if user wants to use points with TeX, % but pointset= is undefined (if the first point doesn't exist) % - no idea what happens if conversion is infinite, % so try to stop at some reasonable value (100?) % - current implementation redefines the points even if only terminal type % has been set to some other value (which is a stupid approach, but I % wanted to have a working version first and will consider efficiency later) % - it may be that the old points remain defined if conversion changes % (perhaps they should be undefined again?) } % Hans has written this piece of code, but: % - "start" and "/MIN" caused problems % - pgnuplot is not much more "portable" than gnuplot % best thing to do is to create a "gnuplot.bat" somewhere in PATH % %\def\processGNUPLOTscript % {\doifelse\operatingsystem{mswin} % {\executesystemcommand{start /MIN pgnuplot \GNUPLOTfile.plt}} % start is needed else gp fails % {\executesystemcommand{gnuplot \GNUPLOTfile.plt}}} %\def\processGNUPLOTscript % {\executesystemcommand{gnuplot \GNUPLOTfile.plt}} % TODO: check if write18 is enabled; if not, issue a command and warn the user that running the module might be pointless or that he/she has to run gnuplot on the produced files manually \def\convertGNUPLOTgraphic {\doifsomething\@@GNUPLOThandle{\writestatus{conversion}{\@@GNUPLOThandle}\executesystemcommand{\@@GNUPLOThandle}}} %D \macros %D {processGNUPLOTfile} %D It's needed to input a file resulting from a gnuplot run (with ConTeXt terminal). %D It reads the file and "saves" the metapost graphics defined in that file, %D so that they can be used with \usegnuplotgraphic (low level: \reuseMPgraphic) later %D % \processGNUPLOTfile[NAME][filename] \def\processGNUPLOTfile {\dodoubleargument\doprocessGNUPLOTfile} \def\doprocessGNUPLOTfile[#1][#2]% {\bgroup % for ConTeXt teminal %-------------------- % we first define two commands: \startGNUPLOTgraphic & \stopGNUPLOTgraphic to read the files in; % files that gnuplot creates in non-standalone mode look approximately like this: % % \startGNUPLOTgraphic[1] % ... metapost commands to draw the graph ... % \stopGNUPLOTgraphic % \startGNUPLOTgraphic[2] % ... metapost commands to draw the graph ... % \stopGNUPLOTgraphic % ... % % while reading the file in, metapost graphics named "gpg:{name}:{number}" are defined % % (we might need some additional arguments later on, but for now the figure number should suffice) \def\startGNUPLOTgraphic {%\obeyMPlines % <- no longer a problem \def\obeyedline{}% <- thanks to this \dosingleargument\dostartGNUPLOTgraphic}% \long\def\dostartGNUPLOTgraphic[##1]##2\stopGNUPLOTgraphic {\startreusableMPgraphic{gpg:#1:##1}##2\stopreusableMPgraphic}% %------------------ % for TikZ terminal %------------------ \newcounter\tikzGNUPLOTnumber \let\normalstarttikzpicture=\starttikzpicture \let\normalstoptikzpicture=\stoptikzpicture \long\def\starttikzpicture##1\stoptikzpicture% {\increment\tikzGNUPLOTnumber % \long\setgvalue{TKZp:#1:\tikzGNUPLOTnumber}{##1}} \long\setgvalue{TKZp:#1:\tikzGNUPLOTnumber}{\hbox{\starttikzpicture##1\stoptikzpicture}}} %--------- % for both %--------- % input the file % TODO: error / warning if the files doesn't exist \readlocfile{#2}{}{}% the third argument should be: if file not found % this file is known % TODO \letgvalue{gpf:#1}\plusone \egroup } %D \macros %D {startGNUPLOTpage} %D %D Used for standalone \GNUPLOT\ figures & written out by gnuplot in standalone mode. %D %D Instead of having to \type{\useGNUPLOTgraphic}, a figure is inserted directly using %D \type{\startMPpage ... }\type{\stopMPpage}. %D %D A high-level command is provided if some more advance features will %D be needed in the future and to be able to ensure backward compatibility. %D We need to preserve line breaks, otherwise metapost runs into troubles for longer input. \def\startGNUPLOTpage {\begingroup\dostartGNUPLOTpage} \long\def\dostartGNUPLOTpage#1\stopGNUPLOTpage {\endgroup\startMPpage#1\stopMPpage} % TODO: use a separate instance for MKIV % % \defineMPinstance[gnuplot] % \startTEXpage\startMPcode{gnuplot} % \stopMPcode\stopTEXpage % TODO: currently, the following definitions are used, % but the ones below would be preferred \def\defineGNUPLOThandle#1#2#3#4#5#6% name; output; suffix; conversion-method; gnuplot's result; final result {\setvalue{@@GNUPLOT-#1}{{#2}{#3}{#4}{#5}{#6}}} \def\@@GNUPLOToutput{\filterfromvalue{@@GNUPLOT-\@@GNUPLOTterminal}51} \def\@@GNUPLOTsuffix{\filterfromvalue{@@GNUPLOT-\@@GNUPLOTterminal}52} \def\@@GNUPLOThandle{\filterfromvalue{@@GNUPLOT-\@@GNUPLOTterminal}53} \def\@@GNUPLOTresult{\filterfromvalue{@@GNUPLOT-\@@GNUPLOTterminal}54} \def\@@GNUPLOTfinalresult{\filterfromvalue{@@GNUPLOT-\@@GNUPLOTterminal}55} % name "set term" suffix conversion (system command) gnuplot's result final result % (suffix is probably not needed any more since full names were introduced) \defineGNUPLOThandle {postscript}{postscript color}{ps}{mtxrun pstopdf \GNUPLOTfile-ps.ps} {\GNUPLOTfile-ps.ps}{\GNUPLOTfile-ps.pdf} \defineGNUPLOThandle {ps}{postscript color}{ps}{mtxrun pstopdf -dAutoRotatePages=/PageByPage \GNUPLOTfile-ps.ps} {\GNUPLOTfile-ps.ps}{\GNUPLOTfile-ps.pdf} \defineGNUPLOThandle {eps}{postscript color eps}{ps}{mtxrun pstopdf -dEPSCrop \GNUPLOTfile-eps.eps} {\GNUPLOTfile-eps.eps}{\GNUPLOTfile-eps.pdf} \defineGNUPLOThandle {pdf}{pdf}{pdf}{} {\GNUPLOTfile-pdf.pdf}{\GNUPLOTfile-pdf.pdf} \defineGNUPLOThandle {pdfcairo}{pdfcairo}{pdf}{} {\GNUPLOTfile-pdfcairo.pdf}{\GNUPLOTfile-pdfcairo.pdf} \defineGNUPLOThandle {metapost}{mp}{mp}{mtxrun mptopdf \GNUPLOTfile-mp.mp} {\GNUPLOTfile-mp.mp}{\GNUPLOTfile-mp-0.pdf} \defineGNUPLOThandle {mp}{mp}{mp}{mtxrun mptopdf \GNUPLOTfile-mp.mp} {\GNUPLOTfile-mp.mp}{\GNUPLOTfile-mp-0.pdf} \defineGNUPLOThandle {png}{png}{png}{} {\GNUPLOTfile-png.png}{\GNUPLOTfile-png.png} \defineGNUPLOThandle {pngcairo}{pngcairo}{png}{} {\GNUPLOTfile-pngcairo.png}{\GNUPLOTfile-pngcairo.png} \defineGNUPLOThandle {tikz}{tikz context createstyle size \@@GNUPLOT@term@tikz@width,\@@GNUPLOT@term@tikz@height\space charsize \the\GNUPLOThcharsize,\the\GNUPLOTvcharsize\space fontscale \@@GNUPLOT@term@tikz@fontscale }{tex}{} {\GNUPLOTfile-tikz.tex}{\GNUPLOTfile-tikz.tex} \defineGNUPLOThandle {context}{context size \@@GNUPLOT@term@context@width,\@@GNUPLOT@term@context@height\space fontscale \@@GNUPLOT@term@context@fontscale }{tex}{} {\GNUPLOTfile-ctx.tex}{\GNUPLOTfile-ctx.tex} % \doifnotempty{\@@GNUPLOT@term@context@fontscale}{fontscale \@@GNUPLOT@term@context@fontscale} \def\defineGNUPLOTterminal {\dodoubleargument\dodefineGNUPLOTterminal} \def\dodefineGNUPLOTterminal[#1][#2]% {\doifassignmentelse{#2}% % define a proper terminal {}% TODO % only define a synonym for that terminal {}% TODO } %D {\sl terminal}: argument to be passed to gnuplot in the form of "set term {\sl terminal}" %D {\sl defaultoptions}: options to be passed to gnuplot after terminal name: %D set term {\sl teminal} {\sl defaultoptions} %D not to be touched by users %D {\sl suffix}: filename suffix %D {\sl result}: the file to which gnuplot should output the result %D set output {\sl result} %D {\sl convertwith}: command for conversion from gnuplot-generated file to a file that can be read by \CONTEXT; may be empty %D {\sl finalresult}: file resulting after the conversion to be read by \CONTEXT %D \POSTSCRIPT\ terminal \defineGNUPLOTterminal [postscript] [terminal=postscript, defaultoptions=color, % TODO: only if \setupcolors[state=start] suffix=ps, result=\GNUPLOTfile-ps.ps, % TODO: -dAutoRotatePages=/PageByPage or remove that option from the default ones convertwith={mtxrun pstopdf \GNUPLOTfile-ps.ps}, finalresult=\GNUPLOTfile-ps.pdf, ] %D Define \type{ps} as a synonym for \type{postscript} terminal \defineGNUPLOTterminal [ps] [postscript] %D \EPS\ terminal: %D - same terminal as for \POSTSCRIPT, but slightly different handling \defineGNUPLOTterminal [eps] [terminal=postscript, defaultoptions=eps color, suffix=eps, result=\GNUPLOTfile-eps.eps, % TODO: -dEPSCrop convertwith={mtxrun pstopdf -dEPSCrop \GNUPLOTfile-eps.eps}, finalresult=\GNUPLOTfile-eps.pdf, ] %D \PDF\ terminal \defineGNUPLOTterminal [pdf] [terminal=pdf, defaultoptions=, suffix=pdf, result=\GNUPLOTfile-pdf.pdf, convertwith=, finalresult=\GNUPLOTfile-pdf.pdf, ] \defineGNUPLOTterminal [pdfcairo] [terminal=pdfcairo, defaultoptions=, suffix=pdf, result=\GNUPLOTfile-pdfcairo.pdf, convertwith=, finalresult=\GNUPLOTfile-pdfcairo.pdf, ] %D \METAPOST\ terminal: %D - deprecated: use the \CONTEXT\ terminal instead, %D which was built starting from the \METAPOST\ one, %D but improved in many aspects \defineGNUPLOTterminal [mp] [terminal=mp, defaultoptions=, suffix=mp, result=\GNUPLOTfile-mp.mp, convertwith={mtxrun mptopdf \GNUPLOTfile-mp.mp}, % TODO: support for multiple graphics % one would need a switch in mptopdf, so that a single pdf would be created instead of multiple ones finalresult=\GNUPLOTfile-mp-0.pdf, ] \defineGNUPLOTterminal [metapost] [mp] %D png terminal: %D - bitmap %D - no conversion needed %D - new version pretty advanced \defineGNUPLOTterminal [png] [terminal=png, defaultoptions=, suffix=png, result=\GNUPLOTfile-png.png, convertwith=, finalresult=\GNUPLOTfile-png.png, ] \defineGNUPLOTterminal [pngcairo] [terminal=pngcairo, defaultoptions=, suffix=png, result=\GNUPLOTfile-pngcairo.png, convertwith=, finalresult=\GNUPLOTfile-pngcairo.png, ] %D \CONTEXT\ terminal (native) \defineGNUPLOTterminal [context] [terminal=context, defaultoptions=, suffix=tex, result=\GNUPLOTfile-ctx.tex, convertwith=, finalresult=\GNUPLOTfile-ctx.tex, ] \def\setupGNUPLOTterminal {\dodoubleargument\dosetupGNUPLOTterminal} \def\dosetupGNUPLOTterminal[#1][#2]% {% TODO \getparameters[@@GNUPLOT@term@#1@][#2] % TODO: width & height % linejoin, linecap - I have to improve this !!! % \edef\gp:term:context:linejoin{\@@GNUPLOT@term@context@linejoin} % \edef\gp:term:context:linecap{\@@GNUPLOT@term@context@linecap} % dashed or solid lines? \doifsamestringelse{\@@GNUPLOT@term@context@dashed}{yes}% yes or no {\edef\@@GNUPLOT@term@context@is@dashed{true}}% {\edef\@@GNUPLOT@term@context@is@dashed{false}}% \doifsamestring{\@@GNUPLOT@term@context@width}{default} {\edef\@@GNUPLOT@term@context@width{5in}} \doifsamestring{\@@GNUPLOT@term@context@height}{default} {\edef\@@GNUPLOT@term@context@height{3in}} % {\edef\gp:term:context:dashed{true}}% % {\edef\gp:term:context:dashed{false}}% % % dashlength scale % \edef\gp:term:context:dashlength{\@@GNUPLOT@term@context@dashlength} % % linewidth scale % \edef\gp:term:context:linewidth{\@@GNUPLOT@term@context@linewidth} % \doifsamestringelse{\@@GNUPLOT@term@context@points}{metapost}% tex or metapost } \setupGNUPLOTterminal [context] [width=default, % *default* (5in) | height=default, % *default* (3in) | linejoin=rounded, % mitered | *rounded* | beveled linecap=butt, % *butt* | rounded (in gnuplot: round) | squared dashed=yes, % *yes* | no dashlength=1, % scaling factor for dash lengths linewidth=1, % scaling factor for line widths (1.0 means 0.4bp) fontscale=1, % scaling factor for text labels points=metapost] % *metapost* | tex (Should points be drawn with MetaPost or TeX?) \setupGNUPLOTterminal [tikz] [width=5in, % *5in* | default (todo) | height=3in, % *3in* | default (todo) | fontscale=1, % scaling factor for text labels ] % TODO: better scaling \defineconversion [gnuplot:pointset] [{\scale[scale=800]{\mathematics{+}}}, {\scale[scale=800]{\mathematics{\times}}}, \mathematics{\ast}, {\scale[scale=700]{\mathematics{\square}}}, {\scale[scale=700]{\mathematics{\blacksquare}}}, \mathematics{\circ}, \mathematics{\bullet}, {\scale[scale=900]{\mathematics{\triangleup}}}, {\scale[scale=900]{\mathematics{\blacktriangle}}}, {\scale[scale=900]{\mathematics{\triangledown}}}, {\scale[scale=900]{\mathematics{\blacktriangledown}}}, {\scale[scale=800]{\mathematics{\lozenge}}}, {\scale[scale=800]{\mathematics{\blacklozenge}}}%, % {\rotate[rotation=45]{\mathematics{\square}}}, % {\rotate[rotation=45]{\mathematics{\blacksquare}}}, ] %\defineGNUPLOTcolor[red] [r=1] %\defineGNUPLOTcolor[green] [g=1] %\defineGNUPLOTcolor[blue] [b=1] %\defineGNUPLOTcolor[magenta][r=1,b=1] %\defineGNUPLOTcolor[cyan] [g=1,b=1] %\defineGNUPLOTcolor[yellow] [r=1,g=1] %\defineGNUPLOTcolor[black] [s=0] %\defineGNUPLOTcolor[orange] [r=1,g=.3,b=0] %\defineGNUPLOTcolor[gray50] [s=.5] %\defineGNUPLOTcolors % [default] % from PostScript % [red,green,blue,magenta,cyan,yellow,black,orange,gray50] % TODO: testset is here only temporary & for testing \setupGNUPLOT[program=gnuplot,\c!terminal=context,\c!purge=\v!yes,\c!options=,\c!pointset=gnuplot:pointset] % colors=postscript %D Some additional typescripts which enable us using font "Arial" and "Helvetica" %D Pretend the font to be serif as well, so that no "ss" switch is needed \starttypescript [serif] [helvetica] [name] \definefontsynonym [Serif] [Helvetica] \definefontsynonym [SerifBold] [Helvetica-Bold] \definefontsynonym [SerifItalic] [Helvetica-Oblique] \definefontsynonym [SerifSlanted] [Helvetica-Oblique] \definefontsynonym [SerifBoldItalic] [Helvetica-BoldOblique] \definefontsynonym [SerifBoldSlanted] [Helvetica-BoldOblique] \definefontsynonym [SerifCaps] [Helvetica] \stoptypescript \starttypescript [gnuplot] \definetypeface [Helvetica] [rm] [serif] [helvetica] [default] \definetypeface [Helvetica] [ss] [sans] [helvetica] [default] \definetypeface [Arial] [rm] [serif] [helvetica] [default] \definetypeface [Arial] [ss] [sans] [helvetica] [default] \stoptypescript \usetypescript[gnuplot] \stopmodule \protect \doifnotmode{demo}{\endinput} \starttext \startGNUPLOTscript[exp] set key bottom set format x "%.1f" set format y "%.1f" set style fill solid 0.25 noborder plot [0:3] 2/sqrt(pi)*exp(-x**2) t '$\frac{2}{\sqrt{\pi}}e^{-x^2}$' with filledcurves x1 lt 3, erf(x) lc 3 lw 2 \stopGNUPLOTscript \useGNUPLOTgraphic[exp][width=.7\textwidth] \startGNUPLOTinclusions set title "trigonometry" \stopGNUPLOTinclusions \startGNUPLOTscript[sin] plot sin(x) \stopGNUPLOTscript \startGNUPLOTscript[cos] plot cos(x) \stopGNUPLOTscript \useGNUPLOTgraphic[sin] \endgraf \useGNUPLOTgraphic[cos] \endgraf \useGNUPLOTgraphic[cos] \endgraf \setupGNUPLOT[terminal=ps] \useGNUPLOTgraphic[sin][object=no,height=2cm] \blank %setupGNUPLOT[terminal=pdf] \useGNUPLOTgraphic[sin][object=no,height=2cm] \blank %setupGNUPLOT[terminal=png] \useGNUPLOTgraphic[sin][object=no,height=2cm] \blank \setupGNUPLOT[terminal=mp] \useGNUPLOTgraphic[sin][object=no,height=2cm,options=color] \blank \stoptext