I'm currently building courses for some of my college teachers. The aim is to make their Word/MS paint generated study material into high grade Latex/Tikz material.
I'm aiming for high consistency in figures (expecially plots) and I've therefore written a bunch of macro's that generate tikz pictures for me from data I get form Matlab
using the matlab2tikz.m
code (which was written at my college!).
What I've done is write a bunch of "set" macro's that set a current variable to be something e.g. \figxlabel{$x$-axis}
(see my code below) would set another macro \thefigxlabel
to contain $x$-axis
. All of this info is then used in the next \matlabfig{data.tikz}
, after which it is reset to neutral values. Since everything is in macro's I don't need to remember what the special settings for a plot were, and even better I can change the \matlabfig
macro to change all pictures at once!
But, then I discovered the Tikz externalize
library which, since my documents are getting large (I split them up but still…), would come in very handy. Yet, this library doesn't support macro usage in tikzpictures.. What would you do to combine the best of two worlds?
I was thinking to use the macro's to set global tikz properties that apply to all figures (I don't know if i can do \tikzset{every xlabel={$x$-axis}}
) and then change this between pictures, so it would only apply to the next one. This way there wouldn't be any macro's inside the tikz environment. I'd have to use a non-macro \begin
and \end
structure then I'm guessing.
All my written macro's are given in the next piece of code (these should work):
\def\figurewidth{7.5cm}
\def\figureheight{4cm}
\newcommand{\thefigtitle}[0]{\null}%title
\newcommand{\thefigtith}[0]{0cm}
\newcommand{\figtitle}[1]{%
\renewcommand{\thefigtitle}{#1}%
\renewcommand{\thefigtith}{0.35cm}%
}
\def\figysep{1}
\newcommand{\thefigxlabel}[0]{\null}%xlabel
\newcommand{\thefigxh}[0]{0}
\newcommand{\figxlabel}[1]{%
\renewcommand{\thefigxlabel}{#1}%
\renewcommand{\thefigxh}{-0.35}%
}
\newcommand{\thefigylabel}{}%ylabel
\newcommand{\figylabel}[1]{\renewcommand{\thefigylabel}{#1}}
\newcommand{\thefiglabel}{ }%label
\newcommand{\figlabel}[1]{%
\renewcommand{\thefiglabel}{\label{#1}}%
}
\newcommand{\thefigxrange}[0]{ }%x-range
\newcommand{\figxrange}[2]{
\renewcommand{\thefigxrange}{xmin=#1,xmax=#2,}
}
\newcommand{\thefigyrange}[0]{ }%y-range
\newcommand{\figyrange}[2]{%
\renewcommand{\thefigyrange}{ymin=#1,ymax=#2,}
}
\newcommand{\thefiglegend}{ }%legend
\newcommand{\figlegend}[2]{%
\renewcommand{\thefiglegend}{legend entries={#1},legend pos={#2}}%
}
\newcommand{\thefigcaption}{\caption{}}%caption
\newcommand{\figcaption}[1]{\renewcommand{\thefigcaption}[0]{\caption{#1}}}
\newcommand{\thefigextra}{ }%extra options
\newcommand{\figextra}[1]{\renewcommand{\thefigextra}[0]{#1}}
\newcommand{\thefigpos}{htp}
\newcommand{\figpos}[1]{\renewcommand{\thefigpos}[0]{#1}}
\newcommand{\matlabfig}[1]{%figuur zelf
\begin{figure}[\thefigpos]
\centering
\begin{tikzpicture}[]
\draw[use as bounding box,draw=none](0,0+\thefigxh)rectangle(\figurewidth,\figureheight+\thefigtith);
\begin{axis}[%
view={0}{90},
scale only axis,
width=\figurewidth,
height=\figureheight,
y tick label style={font={\tiny}},
x tick label style={font={\tiny}},
title={\textbf{\textsc{\thefigtitle}}},
xlabel={\textbf{\thefigxlabel}},
ylabel={\textbf{\thefigylabel}},
\thefigxrange
\thefigyrange
axis on top,\thefiglegend,
\thefigextra,
minor tick num=1
]
\input{#1}
\end{axis}
\end{tikzpicture}
\thefigcaption\thefiglabel
\end{figure}
%alles resetten
\figreset}
\newcommand{\figreset}[0]{
\renewcommand{\thefigtitle}{ }%
\renewcommand{\thefigxlabel}{ }%
\renewcommand{\thefigxh}{0}%
\renewcommand{\thefigtith}{0cm}%
\renewcommand{\thefigylabel}{}%
\renewcommand{\thefigcaption}{\caption{}}%
\renewcommand{\thefiglabel}{}%
\renewcommand{\thefiglegend}{}%
\renewcommand{\thefigxrange}{}%
\renewcommand{\thefigyrange}{}%
\renewcommand{\thefigextra}{ }%
\renewcommand{\thefigpos}{htp}%
}
EDIT: added a working minimal example
contents of example.tex
:
\documentclass{article}
\usepackage{tikz}
\usepackage{pgfplots}
\def\figurewidth{7.5cm}
\def\figureheight{4cm}
\newcommand{\thefigtitle}[0]{\null}%title
\newcommand{\thefigtith}[0]{0cm}
\newcommand{\figtitle}[1]{%
\renewcommand{\thefigtitle}{#1}%
\renewcommand{\thefigtith}{0.45cm}%
}
\def\figysep{1}
\newcommand{\thefigxlabel}[0]{\null}%xlabel
\newcommand{\thefigxh}[0]{0}
\newcommand{\figxlabel}[1]{%
\renewcommand{\thefigxlabel}{#1}%
\renewcommand{\thefigxh}{-0.35}%
}
\newcommand{\thefigylabel}{}%ylabel
\newcommand{\figylabel}[1]{\renewcommand{\thefigylabel}{#1}}
\newcommand{\thefiglabel}{ }%label
\newcommand{\figlabel}[1]{%
\renewcommand{\thefiglabel}{\label{#1}}%
}
\newcommand{\thefigxrange}[0]{ }%x-range
\newcommand{\figxrange}[2]{
\renewcommand{\thefigxrange}{xmin=#1,xmax=#2,}
}
\newcommand{\thefigyrange}[0]{ }%y-range
\newcommand{\figyrange}[2]{%
\renewcommand{\thefigyrange}{ymin=#1,ymax=#2,}
}
\newcommand{\thefiglegend}{ }%legend
\newcommand{\figlegend}[2]{%
\renewcommand{\thefiglegend}{legend entries={#1},legend pos={#2}}%
}
\newcommand{\thefigcaption}{\caption{}}%caption
\newcommand{\figcaption}[1]{\renewcommand{\thefigcaption}[0]{\caption{#1}}}
\newcommand{\thefigextra}{ }%extra options
\newcommand{\figextra}[1]{\renewcommand{\thefigextra}[0]{#1}}
\newcommand{\thefigpos}{htp}
\newcommand{\figpos}[1]{\renewcommand{\thefigpos}[0]{#1}}
\newcommand{\matlabfig}[1]{%figuur zelf
\begin{figure}[\thefigpos]
\centering
\begin{tikzpicture}[]
\draw[use as bounding box,draw=none](0,0+\thefigxh)rectangle(\figurewidth,\figureheight+\thefigtith);
\begin{axis}[%
view={0}{90},
scale only axis,
width=\figurewidth,
height=\figureheight,
y tick label style={font={\tiny}},
x tick label style={font={\tiny}},
title={\textbf{\textsc{\thefigtitle}}},
xlabel={\textbf{\thefigxlabel}},
ylabel={\textbf{\thefigylabel}},
\thefigxrange
\thefigyrange
axis on top,\thefiglegend,
\thefigextra,
minor tick num=1
]
\input{#1}
\end{axis}
\end{tikzpicture}
\thefigcaption\thefiglabel
\end{figure}
%alles resetten
\figreset}
\newcommand{\figreset}[0]{
\renewcommand{\thefigtitle}{ }%
\renewcommand{\thefigxlabel}{ }%
\renewcommand{\thefigxh}{0}%
\renewcommand{\thefigtith}{0cm}%
\renewcommand{\thefigylabel}{}%
\renewcommand{\thefigcaption}{\caption{}}%
\renewcommand{\thefiglabel}{}%
\renewcommand{\thefiglegend}{}%
\renewcommand{\thefigxrange}{}%
\renewcommand{\thefigyrange}{}%
\renewcommand{\thefigextra}{ }%
\renewcommand{\thefigpos}{htp}%
}
\pgfplotsset{
every tick/.style={thin,color=black},
every axis legend/.append style={nodes={right}},
every axis legend/.append style={font=\tiny},
compat=newest
}
\tikzstyle{every node}=[font=\scriptsize]
\begin{document}
%%
\figcaption{an example fig}
\figlabel{fig:example}
\figtitle{example}
\figxlabel{$x$ axis}
\figylabel{$y$ axis}
\figlegend{data.tikz}{north west}
\figxrange{0}{6}
\figyrange{0}{5}
\figextra{}
\matlabfig{data.tikz}
%%
%another fig, but as you can see all was resetted
\matlabfig{data.tikz}
\end{document}
contents of data.tikz
:
\addplot [
color=black,
solid
]
coordinates{(0,0) (3,3) (4,5) (5,4)};
How to to it with environments?
The following example contains the most basic newenvironment
to create a tikzpicture
. What I'm actually going for has a bit more options, but the problem remains the same.
Here's a small piece of sample code:
\documentclass[a4paper]{article}
\usepackage{tikz}
\usetikzlibrary{external}
\newenvironment{mytikz}{%
\begin{figure}[htp]
\centering
\begin{tikzpicture}}
{\end{tikzpicture}
\caption{}
\end{figure}}
\tikzexternalize
\begin{document}
\begin{mytikz}
\draw(0,0) circle (1cm);
\end{mytikz}
\end{document}
Best Answer
The MWE works just fine using the externalisation library. Converting the syntax to use
pgfkeys
actually solves the scoping problem since keys are local to the current scope. Thus you can pass the keys and values as an option to thematlabfig
command and they will be used only internally to that command.I'm only a newcomer to the world of of
pgfkeys
so there may be better ways of implementing this, but here's a conversion of your macros intopgfkeys
language. I only changed one thing in the input syntax: the ranges are specified asx range=0:6
instead ofx range={0}{6}
.When putting this in to an environment, the problem is that the externalisation library looks for
\end{tikzpicture}
without doing any expansion. In an ordinary environment, this doesn't work because the\end{tikzpicture}
is hidden behind a\end{myenvironment}
. So we have to have a method whereby the\end{myenvironment}
is expanded at the same time as the\begin{tikzpicture}
. Fortunately such a method exists and is to use the environ package. This makes environments behave a little like commands.(NB In this code, something is going wrong when I uncomment the bounding box line. It's to do with getting the lengths and values of the keys to interact properly.)