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.

3 Answers 3

9

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}
4
  • 1
    That's exactly what I wanted. Thank you very much. ❤️
    – user193767
    Feb 19, 2020 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.)
    – user194703
    Feb 19, 2020 at 3:34
  • @Schrödinger'scat Very cool parsing technique, thanks!
    – frougon
    Feb 19, 2020 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.)
    – user194703
    Feb 19, 2020 at 21:33
7

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}
1

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.

You must log in to answer this question.