12

I'm in the following situation: Using TikZ, I have drawn a curve which is fairly simply described:

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\draw (1,1.5) .. controls (1,2.25) and (-1,2.25) .. (-1,2)
        node[pos=0,anchor=west]{-1}
        .. controls (-1,1.75) and (1,1.75) .. (1,2.5)
        node[pos=1,anchor=west]{0}
        .. controls (1,3.25) and (-1,3.25) .. (-1,3)
        .. controls (-1,2.75) and (1,2.75) .. (1,3.5)
        node[pos=1,anchor=west]{1};
\end{tikzpicture}
\end{document}

However, now I'd like to specify a different style for part of this curve; It happens that the part of this curve I'd like to do something special with is not easily described explicitly. In this particular case, I'd like to apply the style [(-),thick,red] to some arbitrary segment of the curve. I'm looking for an efficient and simple way to do just that.

I was hoping that there might be an option to do something along the lines of \draw[only between 0.2 and 0.8] "curve description", but I'm not aware of any such possibilities.

For extra concreteness, here is a (Paint-made) picture of something like what I'm looking for:

enter image description here

  • I guess the "best" way involves the use of the decorations library, plus a world of pain to write the code. :) – Alenanno Dec 7 '15 at 22:48
  • @Alenanno That doesn't sound good. Is something along the lines of what I suggest not possible? This problem doesn't sound like something that should be that uncommon... – Danu Dec 7 '15 at 22:53
  • 1
    No, it is possible, but not easy I'm afraid. Look: using this answer, I managed to get this result. With some tweaking you might get a more precise result, but writing that code is not as easy as loading a library. – Alenanno Dec 7 '15 at 23:00
  • @Alenanno My main issue is not the coloring (I may be able to get that done by simply clipping, as has been suggested in chat), but rather the combination of (1) coloring and (2) correct placement of arrow heads – Danu Dec 7 '15 at 23:02
  • You can use marks for the arrow heads. – cfr Dec 8 '15 at 1:31
8

You could try something like this (I don't know if one can combine both decorations in own style):

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{decorations}
\usetikzlibrary{decorations.markings,}

\begin{document}
\begin{tikzpicture}
\draw[postaction={decorate,
                  decoration={markings,
                              mark= at position  5cm with {\arrow[red,thick]{Bar};},
                              mark= at position -2cm with {\arrow[red,thick]{Bar};}}}]
  (1,1.5) .. controls (1,2.25) and (-1,2.25) .. (-1,2)
        node[pos=0,anchor=west]{-1}
        .. controls (-1,1.75) and (1,1.75) .. (1,2.5)
        node[pos=1,anchor=west]{0}
        .. controls (1,3.25) and (-1,3.25) .. (-1,3)
        .. controls (-1,2.75) and (1,2.75) .. (1,3.5)
        node[pos=1,anchor=west]{1};

\path[postaction={decorate,solid,red,draw,thick,
                  decoration={curveto,
                               pre=moveto,pre length=5cm,
                               post=moveto,post length=2cm}, 
                  }                                                        
     ]
  (1,1.5) .. controls (1,2.25) and (-1,2.25) .. (-1,2)
        .. controls (-1,1.75) and (1,1.75) .. (1,2.5)
        .. controls (1,3.25) and (-1,3.25) .. (-1,3)
        .. controls (-1,2.75) and (1,2.75) .. (1,3.5)
    ;

 \end{tikzpicture}

\end{document}

enter image description here

  • as far as I can see, cfr did draw the colored lines between the arrows with a large number of small circles. If you zoom in you can see the difference. – Ulrike Fischer Dec 8 '15 at 15:40
  • Is there a way to modify this so that I can specify how far along the curve I want to place my decoration in terms of fractions rather than in terms of absolute lengths (which is not very insightful for curves such as this one)? – Danu Dec 8 '15 at 15:54
  • Ulrike, you're completely right that your solution is quite different; I'm sorry for confusing the two. I deleted my initial comment. – Danu Dec 8 '15 at 15:55
  • This solution contains the essential idea---namely the curveto decoration---that I needed: I am therefore accepting it. In this particular case, however, I did end up using Mark Wibrow's tweaked version of this idea. – Danu Dec 8 '15 at 20:03
  • This is definitely far superior to my answer. As Ulrike says, mine simulates the line and I was quite surprised it even looked reasonable on the surface. – cfr Dec 8 '15 at 20:31
8

I have shamelessly stolen a considerable part of Ulrike Fischer's answer to illustrate how to specify the ends of the markings using fractions of the path. The basic trick is to multiply fractions by \pgfdecorationpathlength (for decorations) or \pgfmetadecorationpathlength for (meta-decorations) to obtain a length.

In this case I have scaled the fractions first so they fit the range -1 to 1 which matches the node markings. In addition, I have tied everything up in a (not very versatile) style so everything can be done in a single path:

\documentclass[tikz,border=5]{standalone}
\usetikzlibrary{decorations.markings}
\tikzset{mark path between/.style args={#1 and #2}{
  postaction={%
   decorate,
   decoration={markings,
     mark=at position  (#1/2+.5)*\pgfdecoratedpathlength with 
       {\arrow[red,thick]{Bar};},
     mark=at position (#2/2+.5)*\pgfdecoratedpathlength with 
       {\arrow[red,thick]{Bar};}}},
  postaction={decorate,
    solid, red, draw, thick,
    decoration={curveto,
      pre=moveto,pre length=(#1/2+.5)*\pgfmetadecoratedpathlength,
      post=moveto,post length=((-#2)/2+.5)*\pgfmetadecoratedpathlength}}
}}
\begin{document}
\begin{tikzpicture}
\draw [mark path between=-0.25 and 0.5]
  (1,1.5) .. controls (1,2.25) and (-1,2.25) .. (-1,2)
    node[pos=0,anchor=west]{-1}
      .. controls (-1,1.75) and (1,1.75) .. (1,2.5)
    node[pos=1,anchor=west]{0}
      .. controls (1,3.25) and (-1,3.25) .. (-1,3)
      .. controls (-1,2.75) and (1,2.75) .. (1,3.5)
    node[pos=1,anchor=west]{1};
 \end{tikzpicture}
\end{document}

enter image description here

  • This is the solution I went with in the end (after tweaking a little): As you said, the answer was essentially already there in Ulrike's answer, so I accepted that one instead. Nevertheless, I'd like to thank you very much for your answer! – Danu Dec 8 '15 at 20:00
7

Specifically for the arrows, you can use the decorations.markings library with, if desired, arrows.meta for enhanced tip options.

These can be added as single markings or in stepwise fashion. You can measure in absolute units (e.g. 5mm) or as a fraction of path length (e.g. 0.5) and from the start of the path (e.g. 0.6) or from the end (e.g. -0.4). However, they must be added in the order in which they will occur on the path i.e. in the order which they would intuitively be drawn if you walked the path from start to end to add them.

This example illustrates some of the available options:

\documentclass[tikz,border=10pt]{standalone}
\usetikzlibrary{decorations.markings,arrows.meta}
\begin{document}
\begin{tikzpicture}
  \draw [
    postaction=decorate,
    decoration={
      markings,
      mark=at position .1 with {\arrow[red]{<}},
      mark=at position .2 with {\arrow[red]{>}},
      mark=between positions .5 and .7 step .025 with {\arrowreversed[blue]{Stealth[]}},
    }
  ] (1,1.5) .. controls (1,2.25) and (-1,2.25) .. (-1,2)
        node[pos=0,anchor=west]{-1}
        .. controls (-1,1.75) and (1,1.75) .. (1,2.5)
        node[pos=1,anchor=west]{0}
        .. controls (1,3.25) and (-1,3.25) .. (-1,3)
        .. controls (-1,2.75) and (1,2.75) .. (1,3.5)
        node[pos=1,anchor=west]{1};
\end{tikzpicture}
\end{document}

arrow markings

You can apply whatever options you wish to the arrow tips e.g. thick.

If you wish, you can also add something to simulate the line, although I think the plotting solution is probably preferable. For example:

fancier case

\begin{tikzpicture}
  \draw [
    postaction={decorate},
    decoration={
      markings,
      mark=at position .1 with {\arrowreversed[red,thick,xshift=-5pt]{Triangle[length=5pt]}},
      mark=between positions .1 and .2 step .4pt with {\draw [fill,red] circle (.4pt);},
      mark=at position .2 with {\arrow[red,thick,xshift=5pt]{Triangle[length=5pt]}},
      mark=at position .275 with {\arrow[green,thick,xshift=2.5pt]{<}},
      mark=between positions .275 and .375 step .4pt with {\draw [fill,green] circle (.4pt);},
      mark=at position .375 with {\arrow[green,thick,xshift=1pt]{>}},
      mark=between positions .5 and .7 step .025 with {\arrowreversed[blue,thick]{Stealth[]}},
    }
  ] (1,1.5) .. controls (1,2.25) and (-1,2.25) .. (-1,2)
        node[pos=0,anchor=west]{-1}
        .. controls (-1,1.75) and (1,1.75) .. (1,2.5)
        node[pos=1,anchor=west]{0}
        .. controls (1,3.25) and (-1,3.25) .. (-1,3)
        .. controls (-1,2.75) and (1,2.75) .. (1,3.5)
        node[pos=1,anchor=west]{1};
\end{tikzpicture}
  • I only answered because you said you could draw the line by clipping etc. but couldn't combine that with the arrow tips. I suspect there is a much neater solution to this involving a new decoration and/or sub-paths. But that is well beyond me. – cfr Dec 8 '15 at 14:00
  • After the edit, your answer has become much more useful for me :) Thanks a bunch. In particular, this allows me to mark arbitrary curve segments (including the sharp "corners"!). – Danu Dec 8 '15 at 15:28
  • ...but you're right that it seems awfully brute-force to literally just cover the segment in dots... We'll see if anyone shows up with a more elegant solution... – Danu Dec 8 '15 at 15:49
  • 1
    Very brute force and inefficient, for sure. I was interested that the results looked reasonable, though - I was surprised at this despite the high price! – cfr Dec 8 '15 at 20:26
3

If you place enough coordinates along the original line, you can reproduce it accurately.

\documentclass[border=5pt]{standalone}
\usepackage{tikz}
\newcommand{\somelist}{}% reserve global name
\begin{document}
\begin{tikzpicture}
\draw (1,1.5) .. controls (1,2.25) and (-1,2.25) .. (-1,2)
        foreach \i in {0,1,...,10} {coordinate[pos={.4+.03*\i}] (P\i)}
        node[pos=0,anchor=west]{-1}
        .. controls (-1,1.75) and (1,1.75) .. (1,2.5)
        node[pos=1,anchor=west]{0}
        .. controls (1,3.25) and (-1,3.25) .. (-1,3)
        .. controls (-1,2.75) and (1,2.75) .. (1,3.5)
        node[pos=1,anchor=west]{1};
\xdef\somelist{(P0)}
\foreach \i in {1,...,10} {\xdef\somelist{\somelist (P\i)}}
\draw[<->,red] plot[smooth] coordinates{\somelist};
\end{tikzpicture}
\end{document}

reproduced curve

  • Furthermore, this solution does not extend to arbitrary segments of the curve: Putting in \foreach \i in {1,...,35} consistently leads to a bad result (the red arrow doesn't quick manage to bend around like the curve does, and goes off in a wrong direction afterwards). – Danu Dec 8 '15 at 9:27
  • I found out what was breaking my code when trying to implement your answer: You (re)defined the command \list in your solution, but that's already in use by list-like environments (e.g. \itemize and \enumerate). For future reference: Please never use \list as an auxiliary command!! Thanks a lot for your solution, though :) I guess this is what I'll stick to using if nothing better pops up. – Danu Dec 8 '15 at 9:59
  • Sorry about \list. A search revealed \list is used by beamer, fancybox, listings, ieeetrans, varwidth and tikz-timing, all with different definitions. Note that one can create an entirely new list of coordinates by replacing P with some other letter or combination of letters. – John Kormylo Dec 8 '15 at 16:21
1

For comparison, here is a Metapost solution. One can simplify the user interface by defining macros, but I haven't done that.

\starttext
\startMPpage[offset=2mm]
  path p,q;
  numeric n, m[];

  p :=  (1,1.5) .. controls (1,2.25) and (-1,2.25) .. (-1,2)
        .. controls (-1,1.75) and (1,1.75) .. (1,2.5)
        .. controls (1,3.25) and (-1,3.25) .. (-1,3)
        .. controls (-1,2.75) and (1,2.75) .. (1,3.5)
    ;
  q := (0,-0.1) -- (0,0.1);

  p := p scaled 1cm;
  q := q scaled 1cm;

  n = length(p); % Total "time" of the path
  m[1] := 0.2*n; % Value of 0.2 fraction of time
  m[2] := 0.8*n; % Value of 0.8 fraction of time

  % Draw the path in three segments
  draw subpath (0, m[1]) of p ;
  draw subpath (m[1], m[2]) of p withcolor red;
  draw subpath (m[2], n) of p;

  % Draw the decoration
  draw (q rotated (angle direction m[1] of p)) shifted (point m[1] of p)
       withcolor red;
  draw (q rotated (angle direction m[2] of p)) shifted (point m[2] of p)
       withcolor red;

\stopMPpage
\stoptext

which gives

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.