[Tex/LaTex] Control output grid with in pgfplots while doing everything else automatically

pgfplotstikz-pgf

A nice feature of pgfplots is that it automatically chooses reasonable values for maximum/minimum x and y values and for the x and y unit vectors which especially effects the grid size and the labels of the ticks on x and y axis.

On the other hand I know that I can choose the xmin,xmax,... values and the unit vectors manually. I do this for example when I want that the distance of the ticks is exactly 1 cm on the resulting printed paper. See for example my question here: pgfplots axis scaling

However is it possible to combine both things in a reasonable way such that the following hold: Require that pgfplots draws the grid lines such that the distance of the ticks is say 1 cm on the printed paper, but let it do everything else automatically similar like it would normally do such that the resulting plot fits nicely on the page…

Please ask if it is not completely clear what I want (I feel that my english is too bad to make it really clear…)

Edit

Here are two examples, see the comments in the code:

\documentclass{article}

\usepackage{pgfplots}

\begin{document}


%In this example everything is pretty nice, except that the grid on the printed paper is
%not exactly 1cm x 1cm

\begin{tikzpicture}
   \begin{axis}[grid,no markers,samples=100]
      \addplot {exp(x)};
   \end{axis}
\end{tikzpicture}


%In this example the grid size on the printed paper is 1cm x 1cm, which I want, but
%the picture is really too large
\begin{tikzpicture}
   \begin{axis}[grid,no markers,samples=100,x=1cm,y=1cm]
      \addplot {exp(x)};
   \end{axis}
\end{tikzpicture}



%Here I adjusted it manually. But I want that it does this automatically. I don't want to think about what will be the maximum value of the function etc.

\begin{tikzpicture}
   \begin{axis}[grid=both,no markers,samples=100,x=1cm,y=1cm/50,yticks={0,50,...,200}]
      \addplot {exp(x)};
   \end{axis}
\end{tikzpicture}

\end{document}

I don't want to include the output in this case since it is just to large in the second example.

Best Answer

Okay, here's one way of doing it. You'll need to explicitly specify a width and height for the plot, which will be taken as a "target" value for the plot. You might run into problems for plots with very large values or data ranges (if you do, edit your question to include an example and I'll try to fix it).

\documentclass{article}

\usepackage{pgfplots}

\begin{document}

\pgfmathdeclarefunction{nicetick}{1}{%
  \pgfmathsetmacro\exponent{floor(log10(#1))}%
  \pgfmathsetmacro\fraction{#1/(10^\exponent}%
  \pgfmathparse{(10 - (\fraction<5)*5 - (\fraction<2)*3 - (\fraction<1)*1)* 10^\exponent
  }
}

\makeatletter
\pgfplotsset{
    y grid length/.style={
       before end axis/.append code={
            \pgfplotsset{
                calculate/.code={
                    \pgfkeys{/pgf/fpu=true,/pgf/fpu/output format=fixed}
                    \pgfmathparse{\pgfplots@data@ymax-\pgfplots@data@ymin}
                    \let\datarange=\pgfmathresult
                    \pgfmathsetmacro\numberofticks{round(\pgfkeysvalueof{/pgfplots/height}/#1)}
                    \pgfmathsetmacro\niceytick{nicetick( (\datarange)/ (\numberofticks))}
                    \pgfmathsetmacro\minytick{(floor(\pgfplots@data@ymin/\niceytick)-1) * \niceytick}
                    \pgfmathsetmacro\secondytick{\minytick+\niceytick}
                    \pgfmathsetmacro\maxytick{(round(\pgfplots@data@ymax/\niceytick)+1) * \niceytick}
                    \pgfmathsetmacro\yunitlength{#1/\niceytick}
                    \pgfkeys{/pgf/fpu/output format=float,/pgf/fpu=false}       
                },
                calculate,
                y=\yunitlength pt,
                ytick={\minytick,\secondytick,...,\maxytick}
            }
        }   
    },
    x grid length/.style={
       before end axis/.append code={
            \pgfplotsset{
                calculate/.code={
                    \pgfkeys{/pgf/fpu=true,/pgf/fpu/output format=fixed}
                    \pgfmathparse{\pgfplots@data@xmax-\pgfplots@data@xmin}
                    \let\dataxrange=\pgfmathresult
                    \pgfmathsetmacro\numberofticks{round(\pgfkeysvalueof{/pgfplots/width}/#1)}
                    \pgfmathsetmacro\nicextick{nicetick( (\dataxrange)/ (\numberofticks))}
                    \pgfmathsetmacro\minxtick{(floor(\pgfplots@data@xmin/\nicextick)-1) * \nicextick}
                    \pgfmathsetmacro\secondxtick{\minxtick+\nicextick}
                    \pgfmathsetmacro\maxxtick{(round(\pgfplots@data@xmax/\nicextick)+1) * \nicextick}
                    \pgfkeys{/pgf/fpu/output format=float,/pgf/fpu=false}       
                },
                calculate,
                x=#1/\nicextick,
                xtick={\minxtick,\secondxtick,...,\maxxtick}
            }
        }   
    }
}


\begin{tikzpicture}
   \begin{axis}[
        height=4cm,
        width=8cm,
        grid,
        no markers,
        samples=100,
        title=No fixed grid size
    ]
   \addplot {exp(x)};
   \end{axis}
\end{tikzpicture}\\[0.5cm]

\begin{tikzpicture}
   \begin{axis}[
        height=4cm,
        width=8cm,
        grid,
        no markers,
        samples=100,
        x grid length=1cm,
        y grid length=1cm,
        title=Grid size 1\,cm by 1\,cm
    ]
   \addplot {exp(x)};
   \end{axis}
\end{tikzpicture}\\[0.5cm]

\begin{tikzpicture}
   \begin{axis}[
        height=4cm,
        width=8cm,
        grid,
        no markers,
        samples=100,
        x grid length=2cm,
        y grid length=2cm,
        title=Grid size 2\,cm by 2\,cm
    ]
   \addplot {exp(x)};
   \end{axis}
\end{tikzpicture}


\end{document}