7

I am using tikz and would like to draw some straight line segments such that both ends of the segment has 5pt dotted and the rest plain. In pure text, it would be something like

xxx-----------------xxx

I do not want to compute the intermediate points where the changes occur other than by saying it is at fixed distance from the ends.

Thanks, V.

1

3 Answers 3

4

Here is an arrow tip implementation much like How do I draw lines that end with an ellipsis? but with options implemented with the help of \pgfsetarrowoptions and \pgfgetarrowoptions, though you don’t need to use them as I have added three TikZ keys:

  • dotted arrow length: the length of the “arrow”, I guess this is your 5pt.

  • dotted arrow pattern: the pattern used for the dashing.

    This can be used in one of three ways (also on the low level):

    • one single TikZ key like dotted (it actually can be any TikZ key but please don’t …);
    • a dash pattern setting like on 2pt off 3pt on 4pt off 5pt;
    • a \pgfsetdash dash pattern specification like {2pt}{3pt}{4pt}{pt}.
  • dotted arrow phase: the phase of the dashing pattern. If this is empty it is ignored unless the \pgfsetdash specification of above is used, then it is set to +0pt.

Warning: Due to how arrow options are implemented (\csname) you cannot use \pgflinewidth in the dotted arrow pattern option (you can however use \the\pgflinewidth and 4*\the\pgflinewidth instead of 4\pgflinewidth).

You can hide this, though, behind a TikZ style à la

\tikzset{
  my dashing/.style={
    dash pattern=on 4\pgflinewidth off 4\pgflinewidth}}

which I recommend either way.

Code

\documentclass[tikz]{standalone}
\makeatletter
\def\pgfutil@firstofthree#1#2#3{#1}
\def\pgfutil@notfirstofthree#1#2#3{{#2}{#3}}
\def\pgfutil@replace@frstofthr#1#2#3#4{{#4}{#2}{#3}}
\def\pgfutil@replace@scndofthr#1#2#3#4{{#1}{#4}{#3}}
\def\pgfutil@replace@thrdofthr#1#2#3#4{{#1}{#2}{#4}}
\pgfarrowsdeclare{dotted}{dotted}{%
  \edef\pgf@arrow@temp{\pgfgetarrowoptions{dotted}}%
  \edef\pgf@arrow@temp{\expandafter\pgfutil@firstofthree\pgf@arrow@temp}%
  \pgfarrowsleftextend{+0pt}%
  \pgfarrowsrightextend{\pgf@arrow@temp}%
}{%
  \edef\pgf@arrow@temp{\pgfgetarrowoptions{dotted}}%
  \edef\pgf@temp{\expandafter\pgfutil@firstofthree\pgf@arrow@temp}%
  \pgfpathmoveto{\pgfpointorigin}%
  \pgfpathlineto{\pgfpoint{\pgf@temp}{0pt}}%
  \edef\pgf@temp{\expandafter\expandafter\expandafter\pgfutil@firstoftwo\expandafter\pgfutil@notfirstofthree\pgf@arrow@temp}%
  \pgfutil@ifundefined{pgfk@/tikz/\pgf@temp/.@cmd}{% is it a TikZ style?
    \edef\pgf@temp{\expandafter\pgfutil@notfirstofthree\pgf@arrow@temp}%
    \expandafter\pgf@handle@dottedoption\pgf@temp
  }{%
    \let\tikz@options\pgfutil@empty
    \expandafter\tikzset\expandafter{\pgf@temp}%
    \edef\pgf@temp{\expandafter\expandafter\expandafter\pgfutil@secondoftwo\expandafter\pgfutil@notfirstofthree\pgf@arrow@temp}%
    \ifx\pgf@temp\pgfutil@empty\else
      \edef\pgf@arrows@marshal{\noexpand\pgfkeysvalueof{/tikz/dash phase/.@cmd}\pgf@temp\noexpand\pgfeov}%
      \pgf@arrows@marshal
    \fi
    \tikz@options
  }%
  \pgfusepathqstroke}

\def\pgf@handle@dottedoption#1#2{%
  \pgfutil@in@{on}{#1}% maybe it is an "on 2pt off 3pt on 4pt off 5pt" setting?
  \ifpgfutil@in@
    \let\tikz@options\pgfutil@empty
    \pgfkeysvalueof{/tikz/dash pattern/.@cmd}#1\pgfeov
    \edef\pgf@temp{#2}%
    \ifx\pgf@temp\pgfutil@empty\else
      \pgfkeysvalueof{/tikz/dash phase/.@cmd}#2\pgfeov
    \fi
    \tikz@options
  \else % so a low-level PGF setting? Okay ...
    \edef\pgf@temp{#2}%
    \ifx\pgf@temp\pgfutil@empty
      \pgfsetdash{#1}{+0pt}%
    \else
      \pgfsetdash{#1}{#2}%
    \fi
  \fi}

\tikzset{
  dotted arrow length/.code=%
    \edef\tikz@temp{\pgfgetarrowoptions{dotted}}%
    \edef\tikz@temp{\expandafter\pgfutil@replace@frstofthr\tikz@temp{#1}}%
    \edef\tikz@marshal{\noexpand\pgfsetarrowoptions{dotted}{\tikz@temp}}%
    \tikz@marshal,
  dotted arrow pattern/.code=%
    \edef\tikz@temp{\pgfgetarrowoptions{dotted}}%
    \edef\tikz@temp{\expandafter\pgfutil@replace@scndofthr\tikz@temp{#1}}%
    \edef\tikz@marshal{\noexpand\pgfsetarrowoptions{dotted}{\tikz@temp}}%
    \tikz@marshal,
  dotted arrow phase/.code=%
    \edef\tikz@temp{\pgfgetarrowoptions{dotted}}%
    \edef\tikz@temp{\expandafter\pgfutil@replace@thrdofthr\tikz@temp{#1}}%
    \edef\tikz@marshal{\noexpand\pgfsetarrowoptions{dotted}{\tikz@temp}}%
    \tikz@marshal}
\makeatother
\pgfsetarrowoptions{dotted}{{5pt}{densely dotted}{}}
\tikzset{thick}
\begin{document}
\begin{tikzpicture}[gridded]
  \draw [dotted-dotted] (0,0) to[out=10,in=250] (2,2);
\end{tikzpicture}
\begin{tikzpicture}[every path/.append style={arrows=dotted-dotted},y=.2cm]
  \draw (0,3) -- (3,3) [dotted arrow pattern=on .2pt off .2pt on .4pt off .4pt on .6pt off .6pt];
  \draw (0,2) -- (3,2) [dotted arrow length=20pt, dotted arrow pattern=densely dashdotdotted];
  \draw (0,1) -- (3,1) [dotted arrow length=20pt];
  \draw (0,0) -- (3,0);
\end{tikzpicture}

\begin{tikzpicture}[dotted arrow pattern=dont try this at home, dotted arrow length=10pt, dont try this at home/.style={color=red,thick,dash phase=1pt,dotted}]
  \draw[blue, line cap=round, ultra thick, dotted-dotted] (0,0) to[bend left=10] (2,0);
\end{tikzpicture}
\end{document}

Output

enter image description here enter image description here enter image description here

6

Here are two simple methods. One uses a postaction to draw a solid line above a dotted line, while the other uses the calc library to calculate points a given distance away from the end points, and draw solid and dotted lines with those points as starting points.

I wrapped that in a macro so it's easier to use. It could probably be made into a TikZ style or something, but I don't know how. It's not perfect either though, as the end points can be wrong (see example below).

\documentclass[border=2mm,tikz]{standalone}
\usetikzlibrary{calc}
\newcommand\dotandsolid[3][5pt]{%
\coordinate (startofsolidline) at ($(#2)!#1!(#3)$);
\coordinate (endofsolidline) at ($(#3)!#1!(#2)$);
\draw (startofsolidline) -- (endofsolidline);
\draw [densely dotted] (startofsolidline) -- (#2);
\draw [densely dotted] (endofsolidline) -- (#3);
}

\begin{document}
\begin{tikzpicture}
\draw [densely dotted,postaction={draw,solid,shorten >=5pt,shorten <=5pt}] (0,0) -- (1.5,0);
\dotandsolid{0,-0.2}{1.5,-.2}
\dotandsolid[0.5cm]{0,-.4}{1.5,-.4}
\end{tikzpicture}
\end{document}

enter image description here

4
  • Thank you very much! It is very nice and simple to use. But it is also not completely satisfactory: the space between the segment and the first dot is not the same on the left and on the right... Aug 30, 2013 at 16:22
  • @V.Delecroix Yeah, it's by no means an ideal solution. There's a good chance you'll get a more sophisticated answer by one wizard or other though, I don't have any other suggestions at the moment. Aug 30, 2013 at 16:32
  • @TorbjørnT. Ah, I see that in your last edit you are doing something very similar to what I did in my answer... Sorry about that. Aug 30, 2013 at 16:49
  • @GonzaloMedina No need to apologize, it did take me a while to add it. Aug 30, 2013 at 16:53
6

Another option, through a command; the space between the solid line and the first dot on both ends is equal:

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

\newcommand\dotsoldot[3][]{%
  \draw[shorten >=10pt,shorten <=10pt,#1] #2 -- #3;
  \draw[dotted,#1]  ($ #2!10pt!#3 $ ) -- ($ #2!0pt!#3 $ );
  \draw[dotted,#1]  ($ #3!10pt!#2 $ ) -- ($ #3!0pt!#2 $ );
}
\begin{document}

\begin{tikzpicture}
\dotsoldot{(0,0)}{(2.665,0)}
\dotsoldot[red,thick]{(1,2)}{(4,0)}
\end{tikzpicture}

\end{document}

enter image description here

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.