18

I have some automatic placed nodes which should be filled with a pattern. However, I noticed that the pattern offset depends on the node position, which makes the nodes looks different.

Minimal example:

\documentclass[tikz,border=5mm]{standalone}
\usetikzlibrary{patterns}

\begin{document}
\begin{tikzpicture}
\foreach \n in {0,1,...,5}
{
    \node [rectangle,draw,minimum width=1cm,minimum height=1cm,pattern=north west lines] at (1.1*\n cm, 0) {};
    \node [rectangle,draw,minimum width=1cm,minimum height=1cm,pattern=dots] at (1.1*\n cm, 1.1) {};
}
\end{tikzpicture}
\end{document}

How can I achieve that the patterns are drawn identical for every node? I think I have to adjust some pattern origin for that.

Martin Scharrer
  • 262,582
  • I can finally vote on a new question from a moderator. :-) – Sebastiano May 23 '20 at 11:48
  • 1
  • Thanks @steve, looks acutally like a duplicate. If the accepted answer there is right, and TikZ/PGF can't do anything here, I will have to draw the pattern manually, I guess. – Martin Scharrer May 23 '20 at 12:14
  • @MartinScharrer I feel like maybe an alternative would be to make your own patterns in e.g. standalone files, then clip segments of these into your main file; that way, you could control the origin, but also wouldn't have to compile each pattern multiple times. – steve May 23 '20 at 12:22
  • 1
    You can't do that in a predictable way. The origin of the key pattern cell is unspecified and therefore viewer dependent. See also https://github.com/pgf-tikz/pgf/issues/850 If you care about the position of things, don't use patterns. – Henri Menke May 24 '20 at 09:24
  • @HenriMenke The relative features of patterns can be set in a predictable way. To the best of my knowledge, my answer below works across the viewers. The absolute features cannot be controlled, in particular when converting the thingy. That is, we cannot control the distance of the top-left dot from the top-left corner, but we can make sure that all the rectangles look the same. –  May 24 '20 at 17:22

1 Answers1

12

The patterns.meta library has keys that allow one to shift patterns. This works for the Dots pattern. For the Lines pattern the order of transformations in the library is IMHO inconvenient. So I added a version MovableLines, which can be moved in an arguably more intuitive way.1

\documentclass[tikz,border=5mm]{standalone}
\usetikzlibrary{patterns.meta}

\pgfdeclarepattern{
  name=MovableLines,
  parameters={
      \pgfkeysvalueof{/pgf/pattern keys/distance},
      \pgfkeysvalueof{/pgf/pattern keys/angle},
      \pgfkeysvalueof{/pgf/pattern keys/xshift},
      \pgfkeysvalueof{/pgf/pattern keys/yshift},
      \pgfkeysvalueof{/pgf/pattern keys/line width},
  },
  bottom left={%
    \pgfpoint
      {-.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}%
      {-.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}},
  top right={%
    \pgfpoint
      {.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}%
      {.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}},
  tile size={%
    \pgfpoint
      {\pgfkeysvalueof{/pgf/pattern keys/distance}}%
      {\pgfkeysvalueof{/pgf/pattern keys/distance}}},
  tile transformation={%
    \pgftransformshift{%
      \pgfpoint
        {\pgfkeysvalueof{/pgf/pattern keys/xshift}}%
        {\pgfkeysvalueof{/pgf/pattern keys/yshift}}}%
    \pgftransformrotate{\pgfkeysvalueof{/pgf/pattern keys/angle}}},
  defaults={
    distance/.initial=3pt,
    angle/.initial=0,
    xshift/.initial=0pt,
    yshift/.initial=0pt,
    line width/.initial=\the\pgflinewidth,
  },
  code={%
    \pgfsetlinewidth{\pgfkeysvalueof{/pgf/pattern keys/line width}}%
    \pgfpathmoveto{\pgfpoint{-.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}{0pt}}%
    \pgfpathlineto{\pgfpoint{.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}{0pt}}%
    \pgfusepath{stroke}%
  },
}


\begin{document}
\begin{tikzpicture}
\foreach \n in {0,1,...,5}
{
    \node [rectangle,draw,minimum width=1cm,minimum height=1cm,
    pattern={MovableLines[angle=-45,distance={sqrt(0.5)*3pt},
       line width=0.4pt]}] at (1.1*\n cm, 0) {};
    \node [rectangle,draw,minimum width=1cm,minimum height=1cm,
     pattern=Dots] at (1.1*\n cm, 1.1) {};   
}
\end{tikzpicture}

\begin{tikzpicture}
\foreach \n in {0,1,...,5}
{
    \node [rectangle,draw,minimum width=1cm,minimum height=1cm,
    pattern={MovableLines[xshift={1.1*\n cm},angle=-45,distance={sqrt(0.5)*3pt},
       line width=0.4pt]}] at (1.1*\n cm, 0) {};
     \node [rectangle,draw,minimum width=1cm,minimum height=1cm,
     pattern={Dots[xshift={1.1*\n cm}]}] at (1.1*\n cm, 1.1) {};   
}
\end{tikzpicture}

\end{document}

enter image description here

In the upper panel, no shift is applied, and the rectangles look different. In the lower panel we shift according to the horizontal position of the nodes, and the rectangles look the same.

One can also make the pattern transformation part of the definition of the nodes, but this requires some extra work.

Finally, let me mention that patterns are tricky (OK, we know that;-): if you convert the resulting pdf to another format, the patterns may get shifted around.

1One can definitely transform the original lines, too, one just has to backwards engineer the shift. See here for the transformation and the feature request to change the order or add a version that can be shifted in a more intuitive way.

  • 2
    The next version of TikZ/pgf will have the arguably more intuitive order of transformations. That is, if you read this post and already have version 3.1.6 or higher, you can use Lines instead of MovableLines and won't need the definition of the latter. –  May 24 '20 at 06:20