Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I would like to draw two consecutive rectangle nodes (one is next to the other with an intersected edge). How to cut one side of a rectangle node in TikZ so that the intersected side looks like others?

Consider the example below, I don't want the "duplicated" edge between node 1 and 2.

\begin{tikzpicture}

  \node [style={draw, inner sep=0pt, minimum size=0.5cm}]           (1) at (0, 0)  { $1$ };
  \node [style={draw, inner sep=0pt, minimum size=0.5cm}]           (2) at (0.5, 0)  { $2$ };

\end{tikzpicture}
share|improve this question
add comment

2 Answers

up vote 13 down vote accepted

Update:

Here is a better solution, but this has an issue, in that the three sided node lines can be any color you want as long its black :-). The three sided style defined here is based loosely on How to modify nodes in TikZ to automatically add a line on their top?. The corrected node on the right here was drawn as:

  \node [three sided               ] (1) at (0,  0)  { $1$ };
  \node [draw=red, draw opacity=0.5] (2) at (0.5,0)  { $2$ };

enter image description here

Further Enhancements:

  • Allow for other line colors for the three sided node.

Code:

\documentclass{article}
\usepackage{tikz}

\tikzset{three sided/.style={
        draw=none,
        append after command={
            [shorten <= -0.5\pgflinewidth]
            ([shift={(-1.5\pgflinewidth,-0.5\pgflinewidth)}]\tikzlastnode.north east)
        edge([shift={( 0.5\pgflinewidth,-0.5\pgflinewidth)}]\tikzlastnode.north west) 
            ([shift={( 0.5\pgflinewidth,-0.5\pgflinewidth)}]\tikzlastnode.north west)
        edge([shift={( 0.5\pgflinewidth,+0.5\pgflinewidth)}]\tikzlastnode.south west)            
            ([shift={( 0.5\pgflinewidth,+0.5\pgflinewidth)}]\tikzlastnode.south west)
        edge([shift={(-1.0\pgflinewidth,+0.5\pgflinewidth)}]\tikzlastnode.south east)
        }
    }
}

\begin{document} 
\begin{tikzpicture}[thick, inner sep=0pt, minimum size=0.5cm]
  \node [style={draw}] (1) at (0,  0)  { $1$ };
  \node [style={draw=red, draw opacity=0.5}] (2) at (0.5,0)  { $2$ };
\end{tikzpicture}
%
\begin{tikzpicture}[thick, inner sep=0pt, minimum size=0.5cm]
  \node [three sided               ] (1) at (0,  0)  { $1$ };
  \node [draw=red, draw opacity=0.5] (2) at (0.5,0)  { $2$ };
\end{tikzpicture}
\end{document}

You example did not really illustrate the issue, so I have adapted it to more clearly illustrate the issue, and also allows you to see that it is not duplicated in the second version. The two on the left show the problem, and the two on the right should be the desired result:

enter image description here

Note:

  • This is a very manual solution that requires one to use draw=none for the node, followed by a call to \DrawNode to do the actual drawing. There must be some magic postaction that can be applied to have the same effect which woudl simply the usage.
  • Also, I am not sure why you had style={} with the node options.

Code:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}

\newcommand{\DrawNode}[2][]{%
    \draw  [#1]
        ([shift={(-\pgflinewidth,-0.5\pgflinewidth)}]#2.north east) -- 
        ([shift={(0.5\pgflinewidth,-0.5\pgflinewidth)}]#2.north west) -- 
        ([shift={(0.5\pgflinewidth,+0.5\pgflinewidth)}]#2.south west) -- 
        ([shift={(-\pgflinewidth,+0.5\pgflinewidth)}]#2.south east)
        ;
}%

\begin{document} 
\begin{tikzpicture}[thick]
  \node [style={draw, densely dotted, inner sep=0pt, minimum size=0.5cm}] (1) at (0,  0)  { $1$ };
  \node [style={draw=red, draw opacity=0.5, inner sep=0pt, minimum size=0.5cm}] (2) at (0.5,0)  { $2$ };
\end{tikzpicture}
%
\begin{tikzpicture}[thick]
  \node [draw=none, inner sep=0pt, minimum size=0.5cm] (1) at (0,  0)  { $1$ };
  \DrawNode[densely dotted]{1} 
  \node [draw=red, draw opacity=0.5, inner sep=0pt, minimum size=0.5cm] (2) at (0.5,0)  { $2$ };
\end{tikzpicture}

\begin{tikzpicture}[thick]
  \node [style={draw, inner sep=0pt, minimum size=0.5cm}] (1) at (0,  0)  { $1$ };
  \node [style={draw=red, draw opacity=0.5, inner sep=0pt, minimum size=0.5cm}] (2) at (0.5,0)  { $2$ };
\end{tikzpicture}
%
\begin{tikzpicture}[thick]
  \node [draw=none, inner sep=0pt, minimum size=0.5cm] (1) at (0,  0)  { $1$ };
  \DrawNode{1} 
  \node [draw=red, draw opacity=0.5, inner sep=0pt, minimum size=0.5cm] (2) at (0.5,0)  { $2$ };
\end{tikzpicture}
\end{document}
share|improve this answer
1  
Or you could define a new shape with optional sides. –  Andrew Stacey Nov 11 '12 at 18:04
    
Thanks! It helps a lot! –  wei wang Nov 11 '12 at 18:25
    
@AndrewStacey: Yep that too would work, but I don't have much experience with defining shapes. –  Peter Grill Nov 12 '12 at 1:06
add comment

Something along the lines of Peter Grill's updated version I have just noticed …

The style rect takes four arguments that define the styles of the right, top, left and bottom line.
The style rect' is somehow similar but it draws the whole line. I used rect' in the second column to only draw over the already drawn line of the node itself. (This may result in rendering issues depending on the viewer and the zoom level. Mathematically it should draw over the whole line.)
The style rect'' works quite differently as it shortens every line automatically so that they don't overlap, this can be avoided by using the dontshortenme style or the usual shorten ≶ styles. (Additionnaly styles like dontshortenme > and dontshortenme < may be added.)

The style rect has the advantage that every line can have different styles.
The style rect' has the advantage that the normal line would be left alone so that the dot-algorithm isn't used discontinuously. (Compare the dotted lines in the first row.)

The next step would be to check if connect edges have the same style and connect them.

Code

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{etoolbox}
\makeatletter
\tikzset{
    rect/.style n args={4}{
        draw=none,
        rectangle,
        append after command={
            \pgfextra{%
                \pgfkeysgetvalue{/pgf/outer xsep}{\oxsep}
                \pgfkeysgetvalue{/pgf/outer ysep}{\oysep}
                \def\arg@one{#1}
                \def\arg@two{#2}
                \def\arg@three{#3}
                \def\arg@four{#4}
                \begin{pgfinterruptpath}
                    \ifx\\#1\\\else
                        \draw[draw,#1] ([xshift=-\oxsep,yshift=+\pgflinewidth]\tikzlastnode.south east) edge ([xshift=-\oxsep,yshift=0\ifx\arg@two\@empty-\pgflinewidth\fi]\tikzlastnode.north east);
                    \fi\ifx\\#2\\\else
                        \draw[draw,#2] ([xshift=-\pgflinewidth,yshift=-\oysep]\tikzlastnode.north east) edge ([xshift=0\ifx\arg@three\@empty+\pgflinewidth\fi,yshift=-\oysep]\tikzlastnode.north west);
                    \fi\ifx\\#3\\\else
                        \draw[draw,#3] ([xshift=\oxsep,yshift=0-\pgflinewidth]\tikzlastnode.north west) edge ([xshift=\oxsep,yshift=0\ifx\arg@four\@empty+\pgflinewidth\fi]\tikzlastnode.south west);
                    \fi\ifx\\#4\\\else
                        \draw[draw,#4] ([xshift=0+\pgflinewidth,yshift=\oysep]\tikzlastnode.south west) edge ([xshift=0\ifx\arg@one\@empty-\pgflinewidth\fi,yshift=\oysep]\tikzlastnode.south east);
                    \fi
                \end{pgfinterruptpath}
            }
        }
    },
    rect'/.style n args={4}{
        rectangle,
        append after command={
            \pgfextra{%
                \pgfkeysgetvalue{/pgf/outer xsep}{\oxsep}
                \pgfkeysgetvalue{/pgf/outer ysep}{\oysep}
                \begin{pgfinterruptpath}
                    \ifx\\#1\\\else
                        \draw[draw,#1] ([xshift=-\oxsep,yshift=0]\tikzlastnode.south east) edge ([xshift=-\oxsep,yshift=0]\tikzlastnode.north east);
                    \fi\ifx\\#2\\\else
                        \draw[draw,#2] ([xshift=-\pgflinewidth,yshift=-\oysep]\tikzlastnode.north east) edge ([xshift=0+\pgflinewidth,yshift=-\oysep]\tikzlastnode.north west);
                    \fi\ifx\\#3\\\else
                        \draw[draw,#3] ([xshift=\oxsep,yshift=0-\pgflinewidth]\tikzlastnode.north west) edge ([xshift=\oxsep,yshift=0+\pgflinewidth]\tikzlastnode.south west);
                    \fi\ifx\\#4\\\else
                        \draw[draw,#4] ([xshift=0+\pgflinewidth,yshift=\oysep]\tikzlastnode.south west) edge ([xshift=0-\pgflinewidth,yshift=\oysep]\tikzlastnode.south east);
                    \fi
                \end{pgfinterruptpath}
            }
        }
    },
    dontshortenme/.style={
        shorten >=0pt,
        shorten <=0pt
    },
    rect''/.style n args={4}{
        draw=none,
        rectangle,
        append after command={
            \pgfextra{%
                \pgfkeysgetvalue{/pgf/outer xsep}{\oxsep}
                \pgfkeysgetvalue{/pgf/outer ysep}{\oysep}
                \def\my@path{\path[shorten >=\pgflinewidth,shorten <=\pgflinewidth] ([xshift=-\oxsep]\tikzlastnode.south east) edge}
                \def\arg@{#1}
                \ifx\arg@\@empty
                    \def\arg@{draw=none}
                \fi
                \eappto\my@path{[\arg@] }
                \appto\my@path{ ([xshift=-\oxsep]\tikzlastnode.north east)
                                          ([yshift=-\oysep]\tikzlastnode.north east) edge }
                \def\arg@{#2}
                \ifx\arg@\@empty
                    \def\arg@{draw=none}
                \fi
                \eappto\my@path{[\arg@] }
                \appto\my@path{ ([yshift=-\oysep]\tikzlastnode.north west)
                                          ([xshift=\oxsep] \tikzlastnode.north west) edge }
                \def\arg@{#3}
                \ifx\arg@\@empty
                    \def\arg@{draw=none}
                \fi
                \eappto\my@path{[\arg@] }
                \appto\my@path{ ([xshift=\oxsep]\tikzlastnode.south west)
                                          ([yshift=\oysep] \tikzlastnode.south west) edge }
                \def\arg@{#4}
                \ifx\arg@\@empty
                    \def\arg@{draw=none}
                \fi
                \eappto\my@path{[\arg@] }
                \appto\my@path{ ([yshift=\oysep]\tikzlastnode.south east);}
                \begin{pgfinterruptpath}
                    \my@path
                \end{pgfinterruptpath}
            }
        }
    }
}
\makeatother
\tikzset{
    every node/.style={
        inner sep=0pt,
        minimum size=.5cm
    }
}
\begin{document}
\begin{tikzpicture}[thick]
  \node [draw, densely dotted,] (1) at (0,  0)  { $1$ };
  \node [draw=red, draw opacity=0.5] (2) at (0.5,0)  { $2$ };
\end{tikzpicture}
%
\begin{tikzpicture}[thick]
  \node [draw=black, densely dotted, rect'={solid,white}{}{}{}] (1) at (0,  0)  { $1$ };
  \node [draw=red, draw opacity=0.5] (2) at (0.5,0)  { $2$ };
\end{tikzpicture}
%
\begin{tikzpicture}[thick]
  \node [rect={}{densely dotted}{densely dotted}{densely dotted}] (1) at (0,  0)  { $1$ };
  \node [draw=red, draw opacity=0.5] (2) at (0.5,0)  { $2$ };
\end{tikzpicture}
%
\begin{tikzpicture}[thick]
  \node [rect={}{solid,draw=blue}{solid,draw=green}{solid,draw=orange}] (1) at (0,  0)  { $1$ };
  \node [draw=red, draw opacity=0.5] (2) at (0.5,0)  { $2$ };
\end{tikzpicture}
%
\begin{tikzpicture}[thick]
  \node [rect''={}{densely dashed,draw=blue}{draw=green,dontshortenme}{densely dotted,draw=orange}] (1) at (0,  0)  { $1$ };
  \node [draw=red, draw opacity=0.5] (2) at (0.5,0)  { $2$ };
\end{tikzpicture}

\begin{tikzpicture}[thick]
  \node [draw] (1) at (0,  0)  { $1$ };
  \node [draw=red, draw opacity=0.5] (2) at (0.5,0)  { $2$ };
\end{tikzpicture}
%
\begin{tikzpicture}[thick]
  \node [draw=black,rect'={white}{}{}{}] (1) at (0,  0)  { $1$ };
  \node [draw=red, draw opacity=0.5] (2) at (0.5,0)  { $2$ };
\end{tikzpicture}
%
\begin{tikzpicture}[thick]
  \node [rect={}{solid}{solid}{solid}] (1) at (0,  0)  { $1$ };
  \node [draw=red, draw opacity=0.5] (2) at (0.5,0)  { $2$ };
\end{tikzpicture}
%
\begin{tikzpicture}[thick]
  \node [rect={}{solid,draw=blue}{solid,draw=green,shorten >=\pgflinewidth}{solid,draw=orange,shorten <=-\pgflinewidth}] (1) at (0,  0)  { $1$ };
  \node [draw=red, draw opacity=0.5] (2) at (0.5,0)  { $2$ };
\end{tikzpicture}
\end{document}

Output

enter image description here

Peter Grill's example

\begin{tikzpicture}[thick]
  \node [rect={}{solid,draw=blue}{solid,draw=green}{solid,draw=orange}] (1) at (0,  0)  { $1$ };
  \node [draw=red, draw opacity=0.5] (2) at (0.5,0)  { $2$ };
\end{tikzpicture}

Original

enter image description here

Maybe preferred?

\begin{tikzpicture}[thick]
  \node [rect={}{solid,draw=blue}{solid,draw=green,shorten >=\pgflinewidth}{solid,draw=orange,shorten <=-\pgflinewidth}] (1) at (0,  0)  { $1$ };
  \node [draw=red, draw opacity=0.5] (2) at (0.5,0)  { $2$ };
\end{tikzpicture}

enter image description here

Other line ends, new rect'' style

\begin{tikzpicture}[thick]
  \node [rect''={}{densely dashed,draw=blue}{draw=green,dontshortenme}{densely dotted,draw=orange}] (1) at (0,  0)  { $1$ };
  \node [draw=red, draw opacity=0.5] (2) at (0.5,0)  { $2$ };
\end{tikzpicture}

enter image description here

share|improve this answer
    
I think this is better than my version. But rect={}{solid,draw=blue}{solid,draw=green}{solid,draw=orange} results in an error, whereas rect={}{solid,draw=blue}{solid}{solid} produces what I would expect. –  Peter Grill Nov 12 '12 at 19:53
    
@PeterGrill I've updated my code. Apparently, \ifx\\#0\\…\fi isn't the best approach inside of an TikZ-style argument. (By the way, in your example rect={}{blue}{green}{orange} would have had the same output.) I also added a version of your example one would maybe prefer. And here you can see that my code just isn't as perfect as I wished. ;) The joining of lines can be improved. –  Qrrbrbirlbel Nov 12 '12 at 20:17
    
Excellent... BTW, I probably spent three times as much time on tweaking the joining of the lines as I did on the rest of the answer!! –  Peter Grill Nov 12 '12 at 20:21
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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