3

I want to plot a diagram in which I display scattered values within a certain range - these are the maximum values of a measurement I made. From these values, a parameter can be calculated through a formula containing a square root (let's assume y_2=\sqrt{a \cdot y_1}). I would like to show a second y-axis y_2 from which the obtained parameter can directly be read off. I have included an example of what the diagram could look like (created in pyplot).

enter image description here

Unfortunately, I have not yet found a way on how I could obtain a second y-axis for a pgfplot that is not "linearly dependent" on the first y-axis. Does anybody have an idea on what I have to do to generate such a graph with pgfplots?

1 Answer 1

4

It is possible to add annotations to a plot, to place them according to axis coordinates, to retrieve the axis xmin, xmax, ymin and ymax values, etc. Therefore, with a bit of care due to how pgfplots executes code in the axis environment (cf. Utility Commands in chapter Utilities and Basic Level Commands of the pgfplots manual), one can draw this custom secondary scale.

The following code reproduces your plot, where you appear to have used y2 = sqrt(ay1) with a = 5. In order to use this particular function, my code specifies the function and its reciprocal:

declare function={y2(\x) = sqrt(5*\x);
                  y1(\x) = \x^2/5;}

The loop maximum value is automatically determined using the expression given for y2 and the ymax value for the plot. One could do the same to determine the minimum loop value in function of ymin, but I prefer manually setting it to 0, otherwise should you lower ymin below 0, you would obtain errors (trying to take the square root of a negative number).

I use the PGF fpu library in places where computations are done so that this solution has good chances to work as well with other functions where intermediate results might have a very small or a very large magnitude.

Full example:

\documentclass[tikz, border=2mm]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16}

\newif\ifmyInsideAxis

\begin{document}

\begin{tikzpicture}
\begin{axis}[ymin=0, ymax=10, clip=false, grid,
             declare function={y2(\x) = sqrt(5*\x);
                               y1(\x) = \x^2/5;},
             ylabel={$y_1$},
             execute at end axis={
  \edef\myYmin{\pgfkeysvalueof{/pgfplots/ymin}}
  \edef\myYmax{\pgfkeysvalueof{/pgfplots/ymax}}
  %
  \begingroup
  \pgfset{fpu=true}
  % Two values given at the start → the pgfmath parser is used.
  \pgfplotsinvokeforeach {0,1,...,{int(ceil(y2(\myYmax)))}} {
    \pgfmathparse{y1(#1)} \pgfmathfloattofixed{\pgfmathresult}
    \edef\currentY{\pgfmathresult}
    %
    \myInsideAxistrue
    \ifdim \currentY pt>\myYmax pt \myInsideAxisfalse
    \else \ifdim \currentY pt< \myYmin pt \myInsideAxisfalse \fi
    \fi
    %
    \edef\temp{
      \ifmyInsideAxis
        \noexpand\path
          (current axis.east |- 0,0) ++(axis direction cs:0,\currentY)
          coordinate (m);
        \noexpand\draw
          (m) -- ([xshift=\pgfkeysvalueof{/pgfplots/minor tick length}]m)
          node[font=\noexpand\tiny, right] {\noexpand\pgfmathprintnumber{#1}};
      \fi
    }
    {\pgfset{fpu=false} \temp}
  } % end of \pgfplotsinvokeforeach's body
  \endgroup
  }]
\addplot[blue, only marks, mark=square*]
  coordinates { (2,5) (3,7) (4,6) (5,9) (6,8.5) };

\node[rotate=90] at ([xshift=2em]current axis.east) {$y_2 = \sqrt{a y_1}$};
\end{axis}
\end{tikzpicture}

\end{document}

enter image description here

2
  • Thank you very much for your detailed description - I would have never gotten to that solution myself. I tried your example and it worked great! I surely will need some time to fully grasp what you did there to possibly adapt and tweak your solution, but I suppose that I can take the rest from here! Thank you very much!
    – pbaer
    Commented Mar 11, 2020 at 7:58
  • You're welcome! :-)
    – frougon
    Commented Mar 11, 2020 at 8:58

You must log in to answer this question.

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