8

I want to draw grids of arbitrary size using TikZ. I'm using the matrix library and I want to selectively "erase" some lines of it. I post an example of a brute-force solution:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{positioning,matrix}
\begin{document}
\begin{tikzpicture}
    \matrix(lol)[matrix of nodes, nodes in empty cells, row sep=-\pgflinewidth,column sep=-\pgflinewidth,nodes={draw},text width=2em, text height=2em]{
         &  &  &  & \\
         &  &  &  & \\
         &  &  &  & \\
         &  &  &  & \\
    };
    \path[line width = 2pt, draw=white] (lol-2-2.north west) -- (lol-2-2.south west);
    \path[line width = 2pt, draw=white] (lol-3-5.north east) -- (lol-3-5.north west);
    \path[line width = 2pt, draw=white] (lol-3-2.south east) -- (lol-3-2.south west);
\end{tikzpicture}
\end{document}

enter image description here

My solution has two obvious drawbacks:

  1. The white line covers line intersections.
  2. The white line is visible when exporting to other formats, e.g., PNG via ImageMagick.

Although 2 is not really important for me, I want to solve 1 as the grid looks really ugly.

10

You can avoid the unwanted cell borders by just not drawing them. To this end, this answer defines a style pborder, which accepts any combination of the letters t, b, l and r, representing top, bottom, left and right respectively. So

\path (0,4) node[pborder=tbl,font=\sffamily] (tbl) {tbl}
        node[right=of tbl,pborder=br,font=\sffamily] (br) {br};

will produce

enter image description here

and

\matrix(lol)[matrix of nodes, nodes in empty cells,draw,
inner sep=-\pgflinewidth/2,outer sep=0pt,
row sep=-\pgflinewidth,column sep=-\pgflinewidth,
nodes={draw,outer sep=0pt},text width=2em, text height=2em]{
     &  &  &  & \\
   |[pborder=tbl]|  & |[pborder=tbr]|  &  &  & |[pborder=ltr]| \\
     & |[pborder=ltr]| &  &  & |[pborder=lbr]|  \\
     & |[pborder=lbr]|  &  &  & \\
};

enter image description here

So there is absolutely no overpainting whatsoever.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{positioning,matrix}
\usepgfmodule{parser}
\pgfparserdef{matrixborder}{initial}{the letter l}% 
{\draw (path picture bounding box.north west)
-- (path picture bounding box.south west);}% 
\pgfparserdef{matrixborder}{initial}{the letter r}% 
{\draw (path picture bounding box.north east)
-- (path picture bounding box.south east);}% 
\pgfparserdef{matrixborder}{initial}{the letter t}% 
{\draw (path picture bounding box.north west)
-- (path picture bounding box.north east);}% 
\pgfparserdef{matrixborder}{initial}{the letter b}% 
{\draw (path picture bounding box.south west)
-- (path picture bounding box.south east);}% 
\pgfparserdef{matrixborder}{initial}{the character ;}% 
{\pgfparserswitch{final}}
\tikzset{pborder/.style={draw=none,path picture={%
\pgfparserparse{matrixborder}#1;%
}}}
\begin{document}
\begin{tikzpicture}
    \path (0,4) node[pborder=tbl,font=\sffamily] (tbl) {tbl}
        node[right=of tbl,pborder=br,font=\sffamily] (br) {br};
    \matrix(lol)[matrix of nodes, nodes in empty cells,draw,
    inner sep=-\pgflinewidth/2,outer sep=0pt,
    row sep=-\pgflinewidth,column sep=-\pgflinewidth,
    nodes={draw,outer sep=0pt},text width=2em, text height=2em]{
         &  &  &  & \\
       |[pborder=tbl]|  & |[pborder=tbr]|  &  &  & |[pborder=ltr]| \\
         & |[pborder=ltr]| &  &  & |[pborder=lbr]|  \\
         & |[pborder=lbr]|  &  &  & \\
    };
\end{tikzpicture}
\end{document}

enter image description here

You could say that if you want to drop one border there should be a simpler way than adding all the borders that are not to be dropped. This slight extension does this. Now e.g. |[pborder=-r]| drops the border on the right.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{positioning,matrix}
\usepgfmodule{parser}
\newif\ifnegateborder
\negateborderfalse
\pgfparserdef{matrixborder}{initial}{the letter l}% 
{\ifnegateborder
\draw (path picture bounding box.north west)
-- (path picture bounding box.north east) 
|- (path picture bounding box.south west);
\else
\draw (path picture bounding box.north west)
-- (path picture bounding box.south west);
\fi}% 
\pgfparserdef{matrixborder}{initial}{the letter r}% 
{\ifnegateborder
\draw (path picture bounding box.north east)
-- (path picture bounding box.north west)
|- (path picture bounding box.south east);
\else
\draw (path picture bounding box.north east)
-- (path picture bounding box.south east);
\fi}% 
\pgfparserdef{matrixborder}{initial}{the letter t}% 
{\ifnegateborder
\draw (path picture bounding box.north west)
-- (path picture bounding box.south west)
-| (path picture bounding box.north east);
\else
\draw (path picture bounding box.north west)
-- (path picture bounding box.north east);
\fi}% 
\pgfparserdef{matrixborder}{initial}{the letter b}% 
{\ifnegateborder
\draw (path picture bounding box.south west)
-- (path picture bounding box.north west)
-| (path picture bounding box.south east);
\else
\draw (path picture bounding box.south west)
-- (path picture bounding box.south east);
\fi}% 
\pgfparserdef{matrixborder}{initial}{the character -}% 
{\negatebordertrue}%
\pgfparserdef{matrixborder}{initial}{the character ;}% 
{\pgfparserswitch{final}}%
\tikzset{pborder/.style={draw=none,path picture={%
\negateborderfalse
\pgfparserparse{matrixborder}#1;%
}}}
\begin{document}
\begin{tikzpicture}
    \matrix(lol)[matrix of nodes, nodes in empty cells,draw,
    inner sep=-\pgflinewidth/2,outer sep=0pt,
    row sep=-\pgflinewidth,column sep=-\pgflinewidth,
    nodes={draw,outer sep=0pt},text width=2em, text height=2em]{
         &  &  &  & \\
       |[pborder=-r]|  & |[pborder=-l]|  &  &  & |[pborder=-b]| \\
         & |[pborder=-b]| &  &  & |[pborder=-t]|  \\
         & |[pborder=-t]|  &  &  & \\
    };
\end{tikzpicture}
\end{document}
|improve this answer|||||
  • 1
    That's exactly what I wanted. Thank you very much. ❤️ – JairoAraujo Feb 19 at 3:26
  • 2
    @JairoAraujo You're welcome! (I added a small extension that simplifies the syntax if you just want to drop one border.) – Schrödinger's cat Feb 19 at 3:34
  • @Schrödinger'scat Very cool parsing technique, thanks! – frougon Feb 19 at 9:07
  • @frougon The pgfmanual has a lot of stuff which I continuously discover. (This one has already been used here and there, also by me. It is arguably more elegant than all these \ifnextchars and \expandafters.) – Schrödinger's cat Feb 19 at 21:33
8

Not sure exactly why you want to draw over the lines later, but one way you can work around the issue of the edges is to use \shorten to make the line slightly shorter

shorten <= 0.5\pgflinewidth, shorten >= 0.5\pgflinewidth

enter image description here

Code:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{positioning,matrix}

\tikzset{Blank Out Line/.style={line width = 1pt, draw=white, shorten <= 0.5\pgflinewidth, shorten >= 0.5\pgflinewidth}}
\begin{document}
\begin{tikzpicture}
    \matrix(lol)[matrix of nodes, nodes in empty cells, row sep=-\pgflinewidth,column sep=-\pgflinewidth,nodes={draw},text width=2em, text height=2em]{
         &  &  &  & \\
         &  &  &  & \\
         &  &  &  & \\
         &  &  &  & \\
    };
    \path[Blank Out Line] (lol-2-2.north west) -- (lol-2-2.south west);
    \path[Blank Out Line] (lol-3-5.north east) -- (lol-3-5.north west);
    \path[Blank Out Line] (lol-3-2.south east) -- (lol-3-2.south west);
\end{tikzpicture}
\end{document}
|improve this answer|||||
2

This uses shorten, \pgflinewidth (as Peter Grill said above), and line cap=rect, without using matrix library.

enter image description here

\documentclass[tikz,border=5mm]{standalone}
%\pagecolor{gray}     % uncomment for checking
\begin{document}
\begin{tikzpicture}[
%line width=3pt,      % uncomment for checking
line cap=rect]
\draw (0,0) grid (5,4);
\foreach \cutline in {
    (1,2)--+(90:1),
    (1,1)--+(0:1),
    (4,2)--+(0:1)
}
\draw[white,shorten >=\pgflinewidth,shorten <=\pgflinewidth] 
\cutline;
\end{tikzpicture}
\end{document}

enter image description here

PS: No gray strips in pdf file, but there are some when converting to PNG using ImageMagick, even with magick x.pdf -strip x.png command.

|improve this answer|||||

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.