6

I am trying to setup an command to create technical drawing dimensions (inspiration from Dimensioning of a technical drawing in TikZ).

I would like to use pgfkeys for that, in order to pass multiple optional arguments in the same spirit of TikZ.

I works pretty fine (at least I can get what I need) except within an axis environment (from pgfplots). I seems that all pgfkeys from all dimline calls are overridden by the last one.

I am using last MacTex for MacOSX.

I am compiling the source using:

/usr/texbin/xelatex -interaction nonstopmode -shell-escap -output-directory . test3.tex

Any idea why the axis environment zaps all dimline options?

Here is my code:

\documentclass{article}
\usepackage{tikz}
\usepackage{pgfplots}
\usetikzlibrary{calc}

\pgfkeys{
  dimline/.is family,
  dimline,
  dimcolor/.initial = black,
  start line/.initial=1cm,
  start line width/.initial=0.01,
  end line/.initial=1cm,
  end line width/.initial=0.01,
  label pos/.initial={},
}

% #1: optional keys parameters
% #2: start point
% #3: end point
% #4: text

\newcommand{\dimline}[4][]{%

  \pgfkeys{
    dimline,
    #1,
    start line width/.get=\dimlinestartlinewidth,
    start line/.get=\dimlinestartline,
    end line/.get=\dimlineendline,
    end line width/.get=\dimlineendlinewidth,
    label pos/.get=\labelpos,
  }

  \begin{scope}[
    dimrecall/.style={\pgfkeysvalueof{/dimline/dimcolor}},
    dimline/.style={\pgfkeysvalueof{/dimline/dimcolor}},
    ]

    \node (a) at #2 {};
    \node (b) at #3 {};

    \draw [/tikz/dimrecall, line width=\dimlinestartlinewidth]
    (a.center) -- ($(a)!\dimlinestartline!-90:(b)$);
    \draw [dimrecall, line width=\dimlineendlinewidth]
    (b.center) -- ($(b)!\dimlineendline!90:(a)$);

    \draw[|<->|, dimline,] (a.center) -- (b.center)
    node[fill=white, sloped, midway] {\tiny{#4}};
  \end{scope}
}


\begin{document}

Correct without \texttt{axis} environment:

\begin{tikzpicture}
  \draw  (0,0) -- (0,4) -- (.5,4) -- (.5,5) -- (1.,5) -- (1.,4) -- (1.5,4) -- (1.5,0) -- cycle;
  \dimline[dimcolor=blue,start line=-0.25, end line=-0.25]{(3,0)}{(3,4)}{4.0};
  \dimline[dimcolor=red,start line=0.85, end line=0.85]{(0,6)}{(1.5,6)}{1.5};
\end{tikzpicture}


Incorrect within \texttt{axis} environment \texttt{pgfkeys} are overriden:

\begin{tikzpicture}
  \begin{axis} [
    xmin = -1,
    xmax = 8,
    ymin = -1,
    ymax = 8]

    \addplot[mark=none,  color=black] coordinates {
      (0,0)  (0,4) (.5,4) (.5,5) (1.,5) (1.,4) (1.5,4) (1.5,0) (0,0)
    };

    \dimline[dimcolor=blue,start line=-0.25, end line=-0.25]{(axis cs: 3,0)}{(axis cs:3,4)}{4.0};
    \dimline[dimcolor=red,start line=0.85, end line=0.85]{(axis cs: 0,6)}{(axis cs: 1.5,6)}{1.5};

  \end{axis}

\end{tikzpicture}

\end{document}

and the result

image

1

2 Answers 2

7

While Jake's answer is the actual solution to the problem, here is a slight improvement on the UI. Let the macro \dimline deal with

  • if you need to use (axis cs: x, y) or (x, y),
  • if the \pgfplotsextra needs to be applied or not.

The, both the axis and tikzpicture solutions use an identical format:

\dimline[dimcolor=blue,start line=-0.25, end line=-0.25]{3,0}{3,4}{4.0};
\dimline[dimcolor=red,start line=0.85,   end line=0.85 ]{0,6}{1.5,6}{1.5};

to yield:

enter image description here


References:

Notes:

  • The way the coordinates are specified has been changed in that the () around them have been removed. Perhaps there is a way to allow for that as well.

Code:

\documentclass{article}
\usepackage{tikz}
\usepackage{pgfplots}
\usetikzlibrary{calc}

\pgfkeys{
  dimline/.is family,
  dimline,
  dimcolor/.initial = black,
  start line/.initial=1cm,
  start line width/.initial=0.01,
  end line/.initial=1cm,
  end line width/.initial=0.01,
  label pos/.initial={},
}

% #1: optional keys parameters
% #2: start point
% #3: end point
% #4: text


\newcommand{\DoNothing}[1]{#1}%
\newcommand{\dimline}[4][]{%
\pgfplotsifinaxis{%
    \coordinate (a) at (axis cs: #2) {};
    \coordinate (b) at (axis cs: #3) {};
    \let\MyPgfplotsextra\pgfplotsextra%
}{%
    \coordinate (a) at (#2) {};
    \coordinate (b) at (#3) {};
    \def\MyPgfplotsextra#1{#1}%
    \let\MyPgfplotsextra\DoNothing%
}%

\MyPgfplotsextra{
  \pgfkeys{
    dimline,
    #1,
    start line width/.get=\dimlinestartlinewidth,
    start line/.get=\dimlinestartline,
    end line/.get=\dimlineendline,
    end line width/.get=\dimlineendlinewidth,
    label pos/.get=\labelpos,
  }


  \begin{scope}[
    dimrecall/.style={\pgfkeysvalueof{/dimline/dimcolor}},
    dimline/.style={\pgfkeysvalueof{/dimline/dimcolor}},
    ]


    \coordinate (a to b) at ($(a)!\dimlinestartline!-90:(b)$);
    \coordinate (b to a) at ($(b)!\dimlineendline!90:(a)$);

    \draw [dimrecall, line width=\dimlinestartlinewidth]
    (a.center) -- (a to b);
    \draw [dimrecall, line width=\dimlineendlinewidth]
    (b.center) -- (b to a);

    \draw[|<->|, dimline,] (a.center) -- (b.center)
    node[fill=white, sloped, midway] {\tiny{#4}};
  \end{scope}
 }
}


\begin{document}

%Correct without \texttt{axis} environment:

\begin{tikzpicture}
  \draw  (0,0) -- (0,4) -- (.5,4) -- (.5,5) -- (1.,5) -- (1.,4) -- (1.5,4) -- (1.5,0) -- cycle;
  \dimline[dimcolor=blue,start line=-0.25, end line=-0.25]{3,0}{3,4}{4.0};
  \dimline[dimcolor=red,start line=0.85, end line=0.85]{0,6}{1.5,6}{1.5};
\end{tikzpicture}
%
%
%Incorrect within \texttt{axis} environment \texttt{pgfkeys} are overriden:
%
\begin{tikzpicture}
  \begin{axis} [
    xmin = -1,
    xmax = 8,
    ymin = -1,
    ymax = 8]

    \addplot[mark=none,  color=black] coordinates {
      (0,0)  (0,4) (.5,4) (.5,5) (1.,5) (1.,4) (1.5,4) (1.5,0) (0,0)
    };

    \dimline[dimcolor=blue,start line=-0.25, end line=-0.25]{3,0}{3,4}{4.0};
    \dimline[dimcolor=red,start line=0.85, end line=0.85]{0,6}{1.5,6}{1.5};

  \end{axis}

\end{tikzpicture}

\end{document}
2
  • Exactly what I need. Thanks a lot. The icing on the cake would be to compare if the label text box length against the vector length and to change arrow to >-< if the text could not fit in the appropriate length.
    – renard
    Mar 13, 2013 at 23:03
  • @renard: That should be doable, but I think that should be a separate question. Others in the future looking for that issue won't be bale to find if it is buried in here. There are also other things to consider: Besides the case where the text and arrow do not fit, there is the case where text does not fit in the area but the arrows do., then it could be moved to one side, or perhaps above, etc... If the labels are of the form 1.5 cm then perhaps put the 1.5 above and the cm below, etc... Mar 13, 2013 at 23:29
6

In an axis environment, TikZ commands that are reasonably complicated (invoking other macros, for example) should be wrapped inside \pgfplotsextra{...} to make sure that they're executed correctly:

\documentclass{article}
\usepackage{tikz}
\usepackage{pgfplots}
\usetikzlibrary{calc}

\pgfkeys{
  dimline/.is family,
  dimline,
  dimcolor/.initial = black,
  start line/.initial=1cm,
  start line width/.initial=0.01,
  end line/.initial=1cm,
  end line width/.initial=0.01,
  label pos/.initial={},
}

% #1: optional keys parameters
% #2: start point
% #3: end point
% #4: text

\newcommand{\dimline}[4][]{%

  \pgfkeys{
    dimline,
    #1,
    start line width/.get=\dimlinestartlinewidth,
    start line/.get=\dimlinestartline,
    end line/.get=\dimlineendline,
    end line width/.get=\dimlineendlinewidth,
    label pos/.get=\labelpos,
  }

  \begin{scope}[
    dimrecall/.style={\pgfkeysvalueof{/dimline/dimcolor}},
    dimline/.style={\pgfkeysvalueof{/dimline/dimcolor}},
    ]

    \node (a) at #2 {};
    \node (b) at #3 {};

    \draw [/tikz/dimrecall, line width=\dimlinestartlinewidth]
    (a.center) -- ($(a)!\dimlinestartline!-90:(b)$);
    \draw [dimrecall, line width=\dimlineendlinewidth]
    (b.center) -- ($(b)!\dimlineendline!90:(a)$);

    \draw[|<->|, dimline,] (a.center) -- (b.center)
    node[fill=white, sloped, midway] {\tiny{#4}};
  \end{scope}
}


\begin{document}

\begin{tikzpicture}
  \begin{axis} [
    xmin = -1,
    xmax = 8,
    ymin = -1,
    ymax = 8]

    \addplot[mark=none,  color=black] coordinates {
      (0,0)  (0,4) (.5,4) (.5,5) (1.,5) (1.,4) (1.5,4) (1.5,0) (0,0)
    };


    \pgfplotsextra{
            \dimline[dimcolor=blue,start line=-0.25, end line=-0.25]{(axis cs: 3,0)}{(axis cs:3,4)}{4.0};
            \dimline[dimcolor=red,start line=0.85, end line=0.85]{(axis cs: 0,6)}{(axis cs: 1.5,6)}{1.5};
        }

  \end{axis}

\end{tikzpicture}

\end{document}

You must log in to answer this question.

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