# How to keep the line cap when clipping a path?

This question is kind of the opposite of Disable "clip" and "use as bounding box" in TikZ. Is it posisble to clip a path but let the line caps lokk as the path would end at the clipping area.

## basic example

\documentclass[border=10mm]{standalone}

\usepackage{tikz}

\tikzset{line/.style={blue,line width=10mm}}

\begin{document}
\begin{tikzpicture}
\draw (0,0) grid (5,5);
\clip (0,0) rectangle (5,5);
\draw [line] (0,1)  -- (5,4);
\end{tikzpicture}
\end{document}


With the output

but the desired output is

I want to clip a plot in this way and I cannot specify it in a way that the domain equals the clip box, so I must use a clip box, but I don’t want to loose the regular line caps …

## more realistic example

Case 1: I want to set the yrange of the two plots according to the y axis, but gnuplot writes all data points to the table file, even if they are out of range (they are marked with an o in a third column, whereas i indicates that the point is in range). It is possible to set xrange in a way that the plots start at the same y value but this is a lot of try and error, since the xrange mus be found individual for every plot.

Case 2: I got a curve that is define by some points an the first and the last of them must be roots, i.e. y = 0. The problem is that the second root lies out of the axes bounds … I guess I could use the (coord)!pos!(coord) syntax but this is try and error again to let this curve end at the same x value as the plots.

\documentclass[border=10mm]{standalone}

\usepackage{tikz}

\tikzset{line/.style={blue,line width=10mm}}

\begin{document}
\begin{tikzpicture}
\def\yzoom{50}% needed to prevent overflow
% Axes
\draw [<->] (0,0.07*\yzoom) |- (10.5,0);
% Clip
\clip (0,0) rectangle (10,0.07*\yzoom);
% CASE I
% Plots
\draw [line width=2pt,line cap=round]
plot [smooth,raw gnuplot, id=\jobname-plot] function {%
set xrange [1.4:10];
set yrange [0:0.06*\yzoom];
set samples 100;
f(x) = \yzoom*(0.26/(x-1) - 1/(x**2));
plot f(x);
};
\draw [line width=2pt,line cap=round]
plot [smooth,raw gnuplot, id=\jobname-plot] function {%
set xrange [1:10];
set yrange [0:0.06*\yzoom];
set samples 100;
f(x) = \yzoom*(0.28/(x-1) - 1/(x**2));
plot f(x);
};
% CASE II
% Curve, defined by three points.
% P1 and P3 must have y=0
\draw plot coordinates {(2,0) (5,2) (18,0)};
\end{tikzpicture}
\end{document}


Unclipped output:

Clipped output but the round caps are missing …

-
My initial thought is something with the intersection library and automatic line segment creations. However, that is a little laborious if there exists something neater? :) I am hoping that others have a better idea. Great question. –  zeroth Aug 9 '13 at 22:04
Should \draw [line] (-1,.4) -- (5,4); give the same output (same inclination but longer on the left side)? –  Qrrbrbirlbel Aug 9 '13 at 22:23
@Qrrbrbirlbel: Yes, all line should look as if they end at the intersection point with the clip box. –  Tobi Aug 9 '13 at 22:27
It looks like the clipping is done on the lowest level (e.g. PDF, PostScript or SVG), so unless one of these level provides a “smart clip”, this will be a lot of hard work. Can you provide an example where one cannot simply set the right domains? I assume we are not talking about rectangular clip boxes … –  Qrrbrbirlbel Aug 10 '13 at 0:24
The clip boxes are rectangular but the objects to clip are plots so using the intersections library seems impossible in this case. I added a more realistic example to my question … –  Tobi Aug 10 '13 at 1:03

Line caps are not drawn by PGF. They are actually PDF/PS specials. So I'm pretty pessimistic about the possibility of modifying only the line caps such that they survive the clip. Conversely, I don't know any convenient PGF operation that can take a part of a path and save it to overlay over the clip zone. In theory, it is possible to walk over the curve but that's too much work and approximate.

Though you don't prefer it, here is an example just in case it might convince and convert you to the dark side.

\documentclass[border=10mm]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.8}
\pgfplotsset{my style/.style={line width=2pt,line cap=round,no marks,smooth}}
\begin{document}
\begin{tikzpicture}
\begin{axis}[
restrict y to domain= 0:0.15,
axis lines=left,
enlargelimits={abs=0.5mm},
xtick=\empty,ytick=\empty,
axis line style={line width=2pt}
]
\addplot+[my style,domain=1.4:10,samples=100] gnuplot {(0.26/(x-1) - 1/(x**2))};
\addplot+[my style,domain=1.0:10,samples=100] gnuplot {(0.28/(x-1) - 1/(x**2))};
\end{axis}
\end{tikzpicture}
\end{document}


No \yzoom required.

-
Tanks for your answer! It's not that I don't like pgfplots but it seems an overkill for this project since I often need to add non-plot stuff to the canvas (I know the axes cs …) so here I stick to TikZ and keep in mind to use pgfplots for all plots in future … –  Tobi Aug 10 '13 at 10:26

The manual is not exactly correct when it says that “[a]nything following the two numbers on the line [that gnuplot outpus in the .table file] is ignored”. The third column is in fact checked whether it is u (= undefined). If we also check if it is o we can also skip this (or perform some kind of \pgfpathmoveto if this is necessary which it may for plots that exceeds the range midway).

Of course, this is no true smart clipping because the line will clearly not touch the border of the clip box, I had to set the samples to 2000 (which might not be a problem if gnuplot is not called everytime), it is still noticeable, though.

No warranties.

This doesn’t help for the second case but for simple straight lines you might include a macro that pre-processes these three points and instead includes the right plot coordinates.

## Code

\documentclass[tikz,convert=false,border=5mm]{standalone}
\tikzset{line/.style={blue,line width=10mm}}

\makeatletter
\def\pgf@parsegnuplotxyline#1 #2 #3\pgf@stop{%
\edef\pgf@xyline@flag@val{#3}%
\edef\pgf@xyline@flag@undef{u\space}%
\ifx\pgf@xyline@flag@val\pgf@xyline@flag@undef%
\else\edef\pgf@xyline@flag@undef{o\space}% not undef but "o"
\ifx\pgf@xyline@flag@val\pgf@xyline@flag@undef%
%      \let\pgf@plot@first@action=\pgfpathmoveto% maybe needed if you go out of the box and in again
\else
\pgfplotstreampoint{\pgfpointxy{#1}{#2}}%
\fi
\fi%
}
\makeatother
\begin{document}
\begin{tikzpicture}
\def\yzoom{50}% needed to prevent overflow
% Axes
\draw [ultra thick,<->] (0,0.07*\yzoom) |- (10.5,0);
% Clip
\draw[red] (0,0) rectangle (10,0.07*\yzoom);
% CASE I
% Plots
\draw [line width=2pt,line cap=round]
plot [smooth,raw gnuplot, id=\jobname-plot] function {%
set xrange [1.4:10];
set yrange [0:0.07*\yzoom];
set samples 2000;
f(x) = \yzoom*(0.26/(x-1) - 1/(x**2));
plot f(x);
};
\draw [line width=2pt,line cap=round]
plot [smooth,raw gnuplot, id=\jobname-plot] function {%
set xrange [1:10];
set yrange [0:0.07*\yzoom];
set samples 2000;
f(x) = \yzoom*(0.28/(x-1) - 1/(x**2));
plot f(x);
};
%% CASE II
%    % Curve, defined by three points.
%    % P1 and P3 must have y=0
%    \draw plot coordinates {(2,0) (5,2) (18,0)};
\end{tikzpicture}
\end{document}


## Output

-
Thanks! That looks great so far and solves the main issue :-) –  Tobi Aug 10 '13 at 8:20
I hope you don't mind that I accept percusse's answer since it matches the basic question better ... –  Tobi Aug 10 '13 at 10:27