15

I need to plot a pgfplot where the axis arrows “overshoot” the grid by 10pt. Using enlarge x limits I can enlarge the arrows, but then the grid gets enlarged too.

\documentclass[]{standalone}
\usepackage{tikz}
\usepackage{pgfplots}

\begin{document}
\begin{tikzpicture}
\begin{axis}[
    xmin=0, xmax=1, ymin=0, ymax=1,
    axis x line=middle, axis y line=middle,
    enlarge x limits={abs=10pt}, enlarge y limits={abs=10pt},
    minor tick num=1,
    grid=both
    ]
\addplot+[smooth] coordinates{ (0,0) (0.65,.8) (1,1)};  
\end{axis}  
\end{tikzpicture}   
\end{document}

produces

a simple graph

where the grid lines “overshoot” the intended area [0,1]x[0,1].

How can I tell pgfplots to apply enlarge * limits to axis but not to grids?

  • It's not an actual grid but in fact tick lines.So you can put more ticks but don't draw the tick lines – percusse Sep 30 '13 at 12:43
  • I don't think so, adding tick style={red,thick} shows tick at bottom (as expected) but not at top. – Koji Sep 30 '13 at 13:08
  • I mean grid=both means put grid lines at each major and minor ticks. so you can force some of the ticks to have no line. – percusse Sep 30 '13 at 13:37
  • @percusse Yes, but what's in question here in not the number of grid lines (which are OK) but the lengths. Specifically, I want the grid ONLY within the unit square. In other words, can I unapply enlarge x limits to the grid? – Koji Sep 30 '13 at 13:40
  • Ah of course. Nevermind somehow by brain clipped the other ones... – percusse Sep 30 '13 at 15:12
9

You can simply add axis line style={shorten >=-10pt, shorten <=-10pt} to "shorten" the axis lines by -10pt (i.e. lengthening them by 10pt). If you want to position x and y labels at the ends of the axis lines, you'll also need to apply that shift in the xlabel style and ylabel style:

\documentclass[border=1cm]{standalone}
\usepackage{tikz}
\usepackage{pgfplots}

\begin{document}
\begin{tikzpicture}
\begin{axis}[
    xmin=0, xmax=1, ymin=0, ymax=1,
    axis x line=middle, axis y line=middle,
    enlargelimits=false,
    minor tick num=1,
    grid=both,
    axis line style={shorten >=-10pt, shorten <=-10pt},
    xlabel style={
            anchor=west,
            at={(ticklabel* cs:1.0)},
            xshift=10pt
        },
        xlabel=$x$,
        ylabel style={
            anchor=south,
            at={(ticklabel* cs:1.0)},
            yshift=10pt
        },
        ylabel=$y$
    ]
\addplot+[smooth] coordinates{ (0,0) (0.65,.8) (1,1)};  
\end{axis}  
\end{tikzpicture}   
\end{document}
  • neat idea! Now, it needs a little bit more work to work together with xlabels. I had to add xlabel style={anchor=west,at={(ticklabel* cs:1.0)},xshift=10pt},xlabel=$x$to make it work for xlabel and I suppose a similar approach will work for ylabels. Please, add it to your MWE and I'll accept the answer. – Koji Oct 1 '13 at 9:02
  • I should also clarify that this approach is cleanest of all three; since it is possible to add all these elements into a single key style. – Koji Oct 1 '13 at 9:04
  • @Koji: I've edited my answer. – Jake Oct 1 '13 at 11:34
  • 1
    I found additional problems when using shorten. I contribute a detailed discussion and more code below. – Koji Oct 3 '13 at 13:04
4

As it happens, a complete and sufficiently general (for my purposes) answer was quite involved. There are a couple of nuances to deal with.

I provide in this extra answer both some of the problems I found and cut-and-paste code for the unlikely case that someone else is interested in this particular style, but I still think @Jake correctly answered the original question.

  1. When using shorten with a negative value, the axis indeed do overshoot. However, the overshoot does not count toward the bounding box. If you compile a standalone figure, it may well happen that the overshot axis ends up on top of something else. This is dealt with by inserting two “spurious” nodes with before end axis. The x and y labels have to be shifted accordingly.

  2. For this to work properly, you have to choose tick lines at xmin, xmax, ymin, ymax. However, if grid lines and/or ticks lie at the edge of the clip area, they are “half-clipped”, meaning they are half the width they sould be. (see the answer and comments to this question). I found a workaround by removing completely the clipping path from ticks and grids. This is not pretty.

  3. As a consequence of 2, line cap should be round for grids, lest you end up with “ugly corners“ (see here).

  4. As seen below, I implemented three keys overshoot amount, x overshoot and y overshoot. overshoot amount=<length> defines how large should be the overshoot. x overshoot can be set to left, right, noneor both , in case you want overshooting to happen at one side only (see second graphic below). Similarly, y overshootcan be set to top, bottom none or both.

Finally, I am still learning my tikz/pgfplots skills; I am sure my code is ugly. Someone with more pgfplots-fu will surely mend the code.

Code

\documentclass[border=0cm]{standalone}
\usepackage[]{pgfplots}
\makeatletter
\def\pgfplots@drawticklines@INSTALLCLIP@onorientedsurf#1{}%
\def\pgfplots@drawgridlines@INSTALLCLIP@onorientedsurf#1{}%
\makeatother
\pgfplotsset{compat=1.8,
    %%%%
    % Overshooting arrows from grid and ticks
    overshoot amount/.store in=\overshootAmount,
    overshoot amount=4pt,
    %
    x overshoot left/.store in=\xOvershootLeft,
    x overshoot right/.store in=\xOvershootRight,
    x overshoot/.is choice,
    x overshoot/both/.style={x overshoot left=\overshootAmount, x overshoot right=\overshootAmount},
    x overshoot/left/.style={x overshoot left=\overshootAmount, x overshoot right=0pt},
    x overshoot/right/.style={x overshoot left=0pt, x overshoot right=\overshootAmount},
    x overshoot/none/.style={x overshoot left=0pt, x overshoot right=0pt},
    x overshoot=both,
    %
    y overshoot top/.store in=\yOvershootTop,
    y overshoot bottom/.store in=\yOvershootBottom,
    y overshoot/.is choice,
    y overshoot/both/.style={y overshoot top=\overshootAmount, y overshoot bottom=\overshootAmount},
    y overshoot/top/.style={y overshoot top=\overshootAmount, y overshoot bottom=0pt},
    y overshoot/bottom/.style={y overshoot top=0, y overshoot bottom=\overshootAmount},
    y overshoot/none/.style={y overshoot top=0pt, y overshoot bottom=0pt},
    y overshoot=both,
    %%%
    enlargelimits=false,
    every non boxed x axis/.style={
        x axis line style={->,
            black!60!white, thin, line cap=round,
            shorten >=-\xOvershootRight,
            shorten <=-\xOvershootLeft,
        },
        every axis x label/.style={},
        xlabel style={anchor=west,
                at={(ticklabel* cs:1.0)},
            black!60!white,
            xshift=\xOvershootRight
        },
    },
    every non boxed y axis/.style={
        y axis line style={->,
            black!60!white,thin,
            shorten >=-\yOvershootTop,
            shorten <=-\yOvershootBottom,
        },
        every axis y label/.style={},
        ylabel style={
            rotate=0,
            anchor=south,
            at={(ticklabel* cs:1.0)},
            black!60!white,
            yshift=\yOvershootTop
        },
    },
    before end axis/.code={
            \node[inner sep=0pt,at={(rel axis cs:1,1)},xshift=\xOvershootRight, yshift=\yOvershootTop] {};
    \node[inner sep=0pt,at={(rel axis cs:0,0)},xshift=-\xOvershootLeft, yshift=-\yOvershootBottom] {};
    },
    tick style={line cap=round},
    minor tick style={line cap=round},
    %
    grid style={line cap=round},
    minor grid style={line cap=round},
    %
    set layers=standard,
    clip=false,
}


\begin{document}
    \pgfplotsset{overshoot amount=10pt}
\begin{tikzpicture}[baseline]
\begin{axis}[
    axis equal image=true,
    axis x line=middle,
    axis y line=middle,
    xmin=-1, xmax=1, 
    ymin=-1, ymax=1,
    %
    xtick={-1,0,1}, %xticklabels={$-a$,$O$,$a$}, %(if needed)
    ytick={-1,0,1},
    minor tick num=3,
    grid=both, 
    xlabel={$x$}
    ]
\addplot+[smooth] coordinates{ (-.8,.2) (-.3,-.6) (.3,.9) (.8,.7)} ;
\end{axis}
\end{tikzpicture}
%
\begin{tikzpicture}[baseline]
\begin{axis}[
    axis equal image=true,
    axis x line=middle,
    axis y line=middle,
    xmin=0, xmax=1, x overshoot=right,
    ymin=0, ymax=1, y overshoot=top,
    %
    xtick={0,1}, %xticklabels={$-a$,$O$,$a$}, %(if needed)
    ytick={0,1},
    minor tick num=3,
    grid=both, 
    xlabel={$x$}
    ]
\addplot+[smooth] coordinates{ (.1,.6) (.2,.2) (.3,.9) (.8,.7)} ;
\end{axis}
\end{tikzpicture}
\end{document}

Output

overshoot test

  • pretty nice! I should fix my answer too. – percusse Oct 4 '13 at 8:25
2

You can turn on the layers and clip the grid layer with the path you want to limit with. Unfortunately, all online compilers have version 1.5.1 and layers need at least 1.7 so I'm hoping that the following would work. Otherwise the clipping path needs to go inside execute at begin ..., anyone that comes before the grid drawing.

\documentclass[]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.8}
\begin{document}
%\pgfplotsversion
\begin{tikzpicture}
\pgfplotsset{set layers=standard}
\begin{axis}[
    xmin=0, xmax=1, ymin=0, ymax=1,
    axis x line=middle, axis y line=middle,
    enlargelimits={abs=10pt},
    minor tick num=1,
    grid=both
    ]
    \clip[on layer=axis grid] (axis cs:0,0) rectangle (axis cs:1,1);
\addplot+[smooth] coordinates{ (0,0) (0.65,.8) (1,1)};  
\end{axis}  
\end{tikzpicture}   
\end{document}

Please feel free to try and fix this or post another answer and I delete this.

1

This is an alternative.

  1. clip=false is used to turn off the clip effect so that you can extend the x,y axis.

  2. Since an independent pair of new axes are drawn, the arrows need to go and this is done by axis line style={}. Notice that the axis cs system is required to identify the exact coordinates.

  3. Remove the enlarge limits won't affect the "overshot".

Here is the code, followed by a graph.

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

\begin{document}
\begin{tikzpicture}
\begin{axis}[
xmax=1,xmin=0, ymin=0, ymax=1,
axis x line=middle, axis y line=middle,
enlarge x limits={abs=10pt},     enlarge y limits={abs=10pt},
minor tick num=1,
grid=both,  
axis line style={-},                                      % disable arrow
clip=false]                                               % disable clip=true
\addplot+[smooth] coordinates{ (0,0) (0.65,.8) (1,1)};  
\draw[red,->,-stealth] (axis cs:0,0)--(axis cs:0,1.2);    % draw new x axis
\draw[red,->,-stealth] (axis cs:0,0)--(axis cs:1.2,0);    % draw new y axis
\end{axis}  
\end{tikzpicture}   
\end{document}

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.