Use function to scale x axis

Please consider the following plot (code see bottom). The curves are the result of the function q[D]=sqrt(2*s*D/h), whereas h=0.01 and s is equal to 0.1 (blue) respectively 0.01 (green).

Now, I would like to add two more axis on the top of the upper plot as in the following plot. These two axis must be scaled via the function n[D]=D/(q[D])=sqrt(D*h/(2*s)). Maybe there is an alternative workaround of which I did not think up to now?

\documentclass[11pt]{article}
\usepackage{tikz}
\usepackage{pgfplots}

\begin{document}

\begin{tikzpicture}
\begin{axis}[
xlabel=$D$,
ylabel={$q$},axis x line=bottom, axis y line=left
]
\end{axis}
\end{tikzpicture}

\end{document}

-

You can use "dummy" axis environments inside the same tikzpicture to generate the axis lines above the plot. As long as you make sure that the axis ranges are the same, they will align nicely. To get the tick values, you can set xticklabel={\pgfmathparse{sqrt(\tick*0.01/(2*#1))}\pgfmathprintnumber{\pgfmathresult}} which will convert the D value to n(D). That will get you something similar to the Excel output you posted.

To one-up Excel, we can also only plot nice round tick values. We want to be able to specify which ticks to show (0, 1, 1.5 and 2, for example) and let PGFPlots figure out where on the axis these values go. This requires a bit of trickery: We can plot an invisible plot of the inverse of the n(D) function, with the independent variable (in this case n(D)) plotted on the y-axis, and the dependent one (D) plotted on the x axis. By using the option xtick=data, tick labels will only appear at the positions of the samples we specified.

This might seem like a lot of work, but once we've figured it out, we can wrap it in a little macro like \fakexaxis{<value for s>}{<vertical offset>}{<tick positions>} and then simply say

  \begin{axis}[
xlabel=$D$,
ylabel={$q$},axis x line=bottom, axis y line=left
]
\end{axis}

\fakexaxis{0.1}{7ex}{0,1,1.5,2}
\fakexaxis{0.01}{2ex}{0,2,3,...,7}


to generate the following output. I'd say the effort is worth it...

\documentclass[11pt]{article}
\usepackage{tikz}
\usepackage{pgfplots}

\begin{document}

\newcommand{\fakexaxis}[3]{
\begin{axis}[
hide y axis,
yshift=#2,
axis x line=top,
x axis line style={latex-},
xlabel={$s=#1$}, every axis x label/.style={at={(1,1)}, anchor=west},
domain=0:2,
samples at={#3},
xmin=0, xmax=100,
% Convert from D to n(D)
xticklabel={\pgfmathparse{sqrt(\tick*0.01/(2*#1))}\pgfmathprintnumber{\pgfmathresult}},
% tick marks only at sample points
xtick=data
]
% Use the inverse function D = f(n(D)) to find values for D at which to place tick marks (don't actually draw the function)
\end{axis}
}

\begin{tikzpicture}
\begin{axis}[
xlabel=$D$,
ylabel={$q$},axis x line=bottom, axis y line=left
]
\end{axis}

\fakexaxis{0.1}{7ex}{0,1,1.5,2}
\fakexaxis{0.01}{2ex}{0,2,3,...,7}

\end{tikzpicture}

\end{document}

-
very nice approach! many thanks. –  John Feb 8 '13 at 15:12

This is not an answer, but to long for a comment. You could write something yourself, possibly using the \foreach and define function possibilities of TikZ, but I can't get this to work inside the axis. Maybe someone can shed some light?

\documentclass[11pt]{article}
\usepackage{tikz}
\usepackage{pgfplots}

\begin{document}

\pgfmathsetmacro{\h}{0.01}
\pgfmathsetmacro{\sOne}{0.1}
\pgfmathsetmacro{\sTwo}{0.01}

\begin{tikzpicture}[
declare function={
n(\d)= sqrt(\d*\h/(2*\sOne));
}
]
\begin{axis}[
xlabel=$D$,
ylabel={$q$},axis x line=bottom, axis y line=left
]

\end{axis}
\foreach \d in {5, 20, 35, 50, 65, 80, 95}
{
\node at (0.1*\d,-50pt) {\pgfmathparse{n(\d)}\pgfmathresult};
}
\end{tikzpicture}
\end{document}


gives you:

Alternatively, maybe you could compute the ticklabels with another program/script, and include them with xticklabels from table (Section 4.14) in the pgfplotsmanual.

-