2

This is a follow up question on Key names of the axis limits when not set explicitly. The solution as given there works great for regular PGFplots axis environment, but not for a loglog axis enviroment. The \pgfkeysgetvalue{/pgfplots/...}{...} commands within the \pgfplotsextra do not seem to work properly in case of a loglog axis. How do I fix this?

Compiling the code

\documentclass[margin=1cm]{standalone}
\usepackage{amsmath}
\usepackage{pgfplots}

\pgfplotsset{compat=newest}

\usetikzlibrary{calc}

\newcommand{\logLogSlopeTriangle}[9]
{
    % #1. Relative offset in x direction.
    % #2. Width in x direction, so xA-xB.
    % #3. Relative offset in y direction.
    % #4. Slope d(y)/d(log10(x)).
    % #5. Plot options.
    % #6. xmin.
    % #7. xmax.
    % #8. ymin.
    % #9. ymax.

    \pgfplotsextra
    {
        % Calculate auxilliary quantities.
        \pgfmathsetmacro{\xA}{#6^(1-#1)*#7^#1}
        \pgfmathsetmacro{\yA}{#8^(1-#3)*#9^#3}
        \pgfmathsetmacro{\xB}{#6^(1-(#1-#2))*#7^(#1-#2)}
        \pgfmathsetmacro{\yB}{\yA}
        \pgfmathsetmacro{\xC}{\xA}
        \pgfmathsetmacro{\yC}{\yA/(\xB^#4)*\xA^#4}

        % Define coordinates for \draw.
        \coordinate (A) at (axis cs:\xA,\yA);
        \coordinate (B) at (axis cs:\xB,\yB);
        \coordinate (C) at (axis cs:\xC,\yC);

        % Draw slope triangle.
        \draw[#5]   (A)-- node[pos=0.5,anchor=north] {1}
                    (B)-- 
                    (C)-- node[pos=0.5,anchor=west] {#4}
                    cycle;
    }
}

\begin{document}
    \begin{tikzpicture}
        \begin{loglogaxis}
        [
            xmin=10^1, % WHAT IF I DON'T USE THIS?
            xmax=10^4, % WHAT IF I DON'T USE THIS?
            xlabel=$x$,
            ymin=10^0.5, % WHAT IF I DON'T USE THIS?
            ymax=10^4, % WHAT IF I DON'T USE THIS?
            ylabel style={rotate=-90},
            ylabel=$y$,
            grid=major,
            clip=false
        ]
            \addplot[blue,line width=1pt,domain=10^1:10^4] {sqrt(x)};
            \addplot[red,line width=1pt,domain=10^1:10^4] {x};

            %\pgfplotsextra
            %{
                \pgfkeysgetvalue{/pgfplots/xmin}{\xmin}
                \pgfkeysgetvalue{/pgfplots/xmax}{\xmax}
                \pgfkeysgetvalue{/pgfplots/ymin}{\ymin}
                \pgfkeysgetvalue{/pgfplots/ymax}{\ymax}
            %}

            \logLogSlopeTriangle{0.9}{0.1}{0.1}{1/2}{blue}{\xmin}{\xmax}{\ymin}{\ymax};
            \logLogSlopeTriangle{0.75}{0.1}{0.1}{1}{red}{\xmin}{\xmax}{\ymin}{\ymax};

        \end{loglogaxis}
    \end{tikzpicture}
\end{document}

I obtain the desired result

In case I do not want to explicitly specify the axis limits in the axis options, using \pgfplotsextra as desrcibed in Key names of the axis limits when not set explicitly should offer a solution.

Accordingly compiling the code

\documentclass[margin=1cm]{standalone}
\usepackage{amsmath}
\usepackage{pgfplots}

\pgfplotsset{compat=newest}

\usetikzlibrary{calc}

\newcommand{\logLogSlopeTriangle}[9]
{
    % #1. Relative offset in x direction.
    % #2. Width in x direction, so xA-xB.
    % #3. Relative offset in y direction.
    % #4. Slope d(y)/d(log10(x)).
    % #5. Plot options.
    % #6. xmin.
    % #7. xmax.
    % #8. ymin.
    % #9. ymax.

    \pgfplotsextra
    {
        % Calculate auxilliary quantities.
        \pgfmathsetmacro{\xA}{#6^(1-#1)*#7^#1}
        \pgfmathsetmacro{\yA}{#8^(1-#3)*#9^#3}
        \pgfmathsetmacro{\xB}{#6^(1-(#1-#2))*#7^(#1-#2)}
        \pgfmathsetmacro{\yB}{\yA}
        \pgfmathsetmacro{\xC}{\xA}
        \pgfmathsetmacro{\yC}{\yA/(\xB^#4)*\xA^#4}

        % Define coordinates for \draw.
        \coordinate (A) at (axis cs:\xA,\yA);
        \coordinate (B) at (axis cs:\xB,\yB);
        \coordinate (C) at (axis cs:\xC,\yC);

        % Draw slope triangle.
        \draw[#5]   (A)-- node[pos=0.5,anchor=north] {1}
                    (B)-- 
                    (C)-- node[pos=0.5,anchor=west] {#4}
                    cycle;
    }
}

\begin{document}
    \begin{tikzpicture}
        \begin{loglogaxis}
        [
            %xmin=10^1, % WHAT IF I DON'T USE THIS?
            %xmax=10^4, % WHAT IF I DON'T USE THIS?
            xlabel=$x$,
            %ymin=10^0.5, % WHAT IF I DON'T USE THIS?
            %ymax=10^4, % WHAT IF I DON'T USE THIS?
            ylabel style={rotate=-90},
            ylabel=$y$,
            grid=major,
            clip=false
        ]
            \addplot[blue,line width=1pt,domain=10^1:10^4] {sqrt(x)};
            \addplot[red,line width=1pt,domain=10^1:10^4] {x};

            \pgfplotsextra
            {
                \pgfkeysgetvalue{/pgfplots/xmin}{\xmin}
                \pgfkeysgetvalue{/pgfplots/xmax}{\xmax}
                \pgfkeysgetvalue{/pgfplots/ymin}{\ymin}
                \pgfkeysgetvalue{/pgfplots/ymax}{\ymax}
            }

            \logLogSlopeTriangle{0.9}{0.1}{0.1}{1/2}{blue}{\xmin}{\xmax}{\ymin}{\ymax};
            \logLogSlopeTriangle{0.75}{0.1}{0.1}{1}{red}{\xmin}{\xmax}{\ymin}{\ymax};

        \end{loglogaxis}
    \end{tikzpicture}
\end{document}

results in

. As you can see, the triangles are in the wrong place. How do I fix this?

Adriaan
  • 3,675
  • 2
  • 21
  • 41
  • 2
    You have to do the log transformation to the values you have obtained. Print their values or write \show\xmin to see what they hold and compare it with the axis labels. – percusse May 17 '15 at 11:37
  • 1
    Actually, the inverse transformation. \xmin etc. are already log values. (axis cs: \xmin,\ymin) will compute the log of the log. – John Kormylo May 17 '15 at 15:19
  • @percusse I do not understand why with the use of \pgfplotsextra I need other values for the coordinates of triangles. Why does \pgfplotsextra modify this? Nonetheless, I tried to define the coordinates (A), (B) and (C) by (axis cs:10^\xA,10^\yA), (axis cs:10^\xB,10^\yB) and (axis cs:10^\xC,10^\yC)., but this still gives the wrong coordinates. Printing the values with and without \pgfplotsextra, I get for \xA 8.01729000 · 10^0 and 5.01134879 · 10^3 respectively. These numbers do not seem to be related by the log10 or log function. I'm not sure how to proceed. – Adriaan May 17 '15 at 19:22
  • @JohnKormylo Defining the coordinates (A), (B) and (C) by (axis cs:10^\xA,10^\yA), (axis cs:10^\xB,10^\yB) and (axis cs:10^\xC,10^\yC) still gives the wrong coordinates. I do not think the coordinates with and without \pgfplotsextra are related through the log or log10 functions but by another function. I do not know which. What do you think? – Adriaan May 17 '15 at 19:26
  • @JohnKormylo Correction: you should not use (axis cs:10^\xA,10^\yA), but replace \xmin with (exp(\xmin)) instead, to get the proper coordinates (A), (B) and (C), see my answer below. – Adriaan May 18 '15 at 09:25

3 Answers3

2

This is not so much a solution as a demonstration. In the lower right corner are (\xmin,\xmax,\ymin,\ymax) computed without \pgfplotsextra and in the upper right corner with \pgfplotsextra. Using a calculator one can show thet e^\xmin=5 and e^\xmax=20,000, which correspond to the axis limits.

demo

\documentclass{standalone}
\usepackage{pgfplots}
\begin{document}
    \begin{tikzpicture}
        \begin{loglogaxis}
        [
            %xmin=10^1, % WHAT IF I DON'T USE THIS?
            %xmax=10^4, % WHAT IF I DON'T USE THIS?
            xlabel=$x$,
            %ymin=10^0.5, % WHAT IF I DON'T USE THIS?
            %ymax=10^4, % WHAT IF I DON'T USE THIS?
            ylabel style={rotate=-90},
            ylabel=$y$,
            grid=major,
            clip=false
        ]
            \addplot[blue,line width=1pt,domain=10^1:10^4] {sqrt(x)};
            \addplot[red,line width=1pt,domain=10^1:10^4] {x};

            \pgfkeysgetvalue{/pgfplots/xmin}{\xmin}
            \pgfkeysgetvalue{/pgfplots/xmax}{\xmax}
            \pgfkeysgetvalue{/pgfplots/ymin}{\ymin}
            \pgfkeysgetvalue{/pgfplots/ymax}{\ymax}
            \node[above left] at (rel axis cs: 1,0) {(\xmin, \xmax, \ymin, \ymax)};

            \pgfplotsextra
            {
                \pgfkeysgetvalue{/pgfplots/xmin}{\xmin}
                \pgfkeysgetvalue{/pgfplots/xmax}{\xmax}
                \pgfkeysgetvalue{/pgfplots/ymin}{\ymin}
                \pgfkeysgetvalue{/pgfplots/ymax}{\ymax}
                \node[below left] at (rel axis cs: 1,1) {(\xmin, \xmax, \ymin, \ymax)};
            }

        \end{loglogaxis}

    \end{tikzpicture}
\end{document}
John Kormylo
  • 79,712
  • 3
  • 50
  • 120
  • There is nothing in the lower right corner :(. Nonetheless, because of your remark, I again checked if the transformation in question is exp(..), and indeed, it turns out it is. Replacing \xmin with (exp(\xmin)) and similiar for the other limits, I get the proper coordinates. I'll post this solution as an answer. – Adriaan May 18 '15 at 09:46
2

The correct code seems to be

\documentclass[margin=1cm]{standalone}
\usepackage{amsmath}
\usepackage{pgfplots}

\pgfplotsset{compat=newest}

\usetikzlibrary{calc}

\newcommand{\logLogSlopeTriangle}[5]
{
    % #1. Relative offset in x direction.
    % #2. Width in x direction, so xA-xB.
    % #3. Relative offset in y direction.
    % #4. Slope d(y)/d(log10(x)).
    % #5. Plot options.

    \pgfplotsextra
    {
        \pgfkeysgetvalue{/pgfplots/xmin}{\xmin}
        \pgfkeysgetvalue{/pgfplots/xmax}{\xmax}
        \pgfkeysgetvalue{/pgfplots/ymin}{\ymin}
        \pgfkeysgetvalue{/pgfplots/ymax}{\ymax}    

        % Calculate auxilliary quantities.
        \pgfmathsetmacro{\xA}{(exp(\xmin))^(1-#1)*(exp(\xmax))^#1}
        \pgfmathsetmacro{\yA}{(exp(\ymin))^(1-#3)*(exp(\ymax))^#3}
        \pgfmathsetmacro{\xB}{(exp(\xmin))^(1-(#1-#2))*(exp(\xmax))^(#1-#2)}
        \pgfmathsetmacro{\yB}{\yA}
        \pgfmathsetmacro{\xC}{\xA}
        \pgfmathsetmacro{\yC}{\yA/(\xB^#4)*\xA^#4}

        % Define coordinates for \draw.
        \coordinate (A) at (axis cs:\xA,\yA);
        \coordinate (B) at (axis cs:\xB,\yB);
        \coordinate (C) at (axis cs:\xC,\yC);

        % Draw slope triangle.
        \draw[#5]   (A)-- node[pos=0.5,anchor=north] {1}
                    (B)-- 
                    (C)-- node[pos=0.5,anchor=west] {#4}
                    cycle;
    }
}

\begin{document}
    \begin{tikzpicture}
        \begin{loglogaxis}
        [
            xlabel=$x$,
            ylabel style={rotate=-90},
            ylabel=$y$,
            grid=major,
            clip=false
        ]
            \addplot[blue,line width=1pt,domain=10^1:10^2] {sqrt(x)};
            \addplot[red,line width=1pt,domain=10^1:10^2] {x};

            \logLogSlopeTriangle{0.9}{0.1}{0.1}{0.5}{blue};
            \logLogSlopeTriangle{0.75}{0.1}{0.1}{1}{red};
        \end{loglogaxis}
    \end{tikzpicture}
\end{document}

, where I replaced \xmin with (exp(\xmin)), \xmax with (exp(\xmax)), \ymin with (exp(\ymin)) and \ymax with (exp(\ymax)).

Apparently, using \pgfplotsextra gives the axis limits in log(...) so that exp(...) needs to be applied to get the proper local coordinates.

The result looks like:

Adriaan
  • 3,675
  • 2
  • 21
  • 41
1

\pgfplotsextra is, roughly, the pgfplots command of the TikZ/PGF equivalent \pgfextra.

There are two things interacting here. First of all, when it comes to path drawing execution, pgfplots is not TikZ for a very good reason. Because it has to create an axis based on the plotted entities such that the paths are tightly encapsulated by the axis limits, ticks,grid lines and tick labels are automatically computed and so on. To be able to do this, pgfplots harvests all the possible things that will be drawn until the axis environment is finished.

Then starts evaluating the max values the limits etc. and prepares the axis and then but only then starts protocolling the collected items to PGF as drawing commands. So in the end what you see is bunch of PGF paths drawn inside a TikZ picture.

TikZ however doesn't have this behavior. When you issue a path command it immediately sends the relevant driver commands and PDF specials are commanded. In the \pgfextra case this is needed to postpone the current path construction execute the argument of \pgfextra (say some definitions are changed or some conputations are performed and defined) then resume the path construction.

In pgfplots case this is needed to stream the native TikZ drawing commands together with the plotting objects of pgfplots such that they are also executed after the axis collection is finished. For example, the xmin,xmax values are not set before axis is finished and probably you will read the default values, if not zero.

That is in essence why it is needed to use \pgfplotsextra otherwise as you have experienced all the numbers and dimensions etc. are uninitiated however parsing is still done with pgfplots hence you get strange shaped paths (I think here they are all log() versions instead of the actual units but didn't check).

Important to note that pgfplots is usually clever enough to do the \pgfplotsextra addition automatically when it encounters TikZ path commands. But if there is additional data is required that are computed after the axis finished it cannot help further.

In your case, there are much easier alternatives:

  1. If the plots are mostly linear then place coordinates on the plot and do whatever is needed

  2. If you have complicated plots that needs tangents and other complications use decorations.

For the first case an example :

\documentclass[margin=1cm]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.12}
\begin{document}
  \begin{tikzpicture}
    \begin{loglogaxis}[
    xlabel=$x$,
    ylabel style={rotate=-90},
    ylabel=$y$,
    grid=major,
    ]
      \addplot[blue,line width=1pt,domain=10^1:10^4] {sqrt(x)} 
         coordinate[pos=0.50] (a) 
         coordinate[pos=0.75] (b);
      \draw[blue] (a) -| (b) 
         node[pos=0.25,below] {1} 
         node[pos=0.75,right] {2}; % Or whatever complicated label

    \end{loglogaxis}
  \end{tikzpicture}
\end{document}

enter image description here

percusse
  • 157,807
  • Thank you for your clear explanation and example code. However, my figures contain multiple graphs with different slopes and some intersections. Because of this, there is no space to annotate triangles like you did in your answer. This is why I chose to try to put the annotations in the lower right corner, where there is some left space. – Adriaan May 18 '15 at 09:29