8

I got a image as below from internet,but I am not sure which tool is used to drawing it. Does Tikz has such library to do it? Or how can we draw it in Tikz effectively.

enter image description here

18

Improved version

(Older versions can be seen in the edit history of this answer)

enter image description here

This image was produced with the code (explanations at the bottom):

\begin{timeline}
\TimeLine{%
    1/red1/{},%
    2/red2/{},%
    8/yellow1/{30--60 days},%
    1/yellow2/{},%
    12/yellow3/{30--90 days},%
    4/green1/{10--30 days},%
    6/green2/{30--45 days}%
  }
\AddText[text=white]{red1}{Initial \\ meeting}{2}{L}
\AddText{red2}{List \\ property}{2}{m}
\AddText{yellow1}{Listing \\ period}{3}{M}
\AddText{yellow2}{Offer \\ received}{4}{L}
\AddText{yellow2}{Offer \\ signed}{4}{m}
\AddText{yellow3}{File under \\ review}{5}{M}
\AddText[xshift=-3pt]{green1}{Negotiator \\ assigned}{6}{L}
\AddText{green1}{Offer in final \\ review}{6}{m}
\AddText[xshift=3pt]{green2}{Short sale\\ approved}{7}{L}
\AddText{green2}{Under \\ contract}{7}{m}
\AddText[text=white]{green2!80!black}{Vacate \& \\ close}{7}{R}
\end{timeline}

The complete code:

\documentclass[tikz,border=5pt]{standalone}
\usetikzlibrary{calc,positioning,shapes.multipart,decorations.pathreplacing,shapes.arrows}

\definecolor{red1}{RGB}{195,0,0}
\definecolor{red2}{RGB}{246,136,93}
\definecolor{yellow1}{RGB}{247,175,47}
\definecolor{yellow2}{RGB}{255,192,96}
\definecolor{yellow3}{RGB}{255,255,96}
\definecolor{green1}{RGB}{214,249,121}
\definecolor{green2}{RGB}{113,158,65}

% vertical separation between timeline and text boxes
\def\TextShift{15pt}

\tikzset{
  myrect/.style={
    rectangle split, 
    rectangle split horizontal,
    rectangle split parts=#1,
    draw,
    anchor=west,
  },
  mytext/.style={
    arrow box,
    draw=#1!70!black,
    fill=#1,
    align=center,
    line width=1pt,
    font=\sffamily
  },
  mytextb/.style={
    mytext=#1,
    anchor=north,
    arrow box arrows={north:0.5cm}  
  },
  mytexta/.style={
    mytext=#1,
    anchor=south,
    arrow box arrows={south:0.5cm}  
  }
}

\newcommand\AddTextA[4][]{
  \node[mytexta=#2,#1] at #3 {#4};
}
\newcommand\AddTextB[4][]{
  \node[mytextb=#2,#1] at #3 {#4};
}
\newcommand\AddText[5][]{
  \if#5l\relax
    \node[mytextb=#2,yshift=-\TextShift,#1] 
      at (part#4.south west) {\strut#3\strut};
  \fi
  \if#5L\relax
    \node[mytexta=#2,yshift=\TextShift,#1] 
      at (part#4.north west) {\strut#3\strut};
  \fi
  \if#5m\relax
    \node[mytextb=#2,yshift=-\TextShift,#1] 
      at ( $ (part#4.south west)!0.5!(part#4.south east) $ ) {\strut#3\strut};
  \fi
  \if#5M\relax
    \node[mytexta=#2,yshift=\TextShift,#1] 
      at ( $ (part#4.north west)!0.5!(part#4.north east) $ ) {\strut#3\strut};
  \fi
  \if#5r\relax
    \node[mytextb=#2,yshift=-\TextShift,#1] 
      at (part#4.south east) {\strut#3\strut};
  \fi
  \if#5R\relax
    \node[mytexta=#2,yshift=\TextShift,#1] 
      at (part#4.north east) {\strut#3\strut};
  \fi
}

\newcommand\TimeLine[1]{%
\coordinate (part0);  
\foreach \Longitud/\Color/\Texto [count=\ti] in {#1}
{
  \node[
    myrect=\Longitud,
    fill=\Color,
    right=of part\the\numexpr\ti-1\relax
    ] 
      (part\ti)
      {};
  \draw 
    ([yshift=-15pt]part\ti.east) coordinate (upper\ti) -- 
    ([yshift=15pt]part\ti.east) coordinate (lower\ti);
  \node[font=\footnotesize]
    at (part\ti.center) {\Texto};  
  \gdef\lastpart{\ti}
}
\foreach \Nodo in {2,...,\lastpart}
{
  \ifodd\Nodo\relax
  \draw[decoration={brace,mirror},decorate] 
    (lower\Nodo) -- (lower\the\numexpr\Nodo-1\relax);
  \else
  \draw[decoration=brace,decorate] 
    (upper\Nodo) -- (upper\the\numexpr\Nodo-1\relax);
  \fi    
}
}

\newenvironment{timeline}[1][]
  {\begin{tikzpicture}[node distance=0pt and -\pgflinewidth,#1]}
  {\end{tikzpicture}}

\begin{document}

\begin{timeline}
\TimeLine{%
    1/red1/{},%
    2/red2/{},%
    8/yellow1/{30--60 days},%
    1/yellow2/{},%
    12/yellow3/{30--90 days},%
    4/green1/{10--30 days},%
    6/green2/{30--45 days}%
  }
\AddText[text=white]{red1}{Initial \\ meeting}{2}{L}
\AddText{red2}{List \\ property}{2}{m}
\AddText{yellow1}{Listing \\ period}{3}{M}
\AddText{yellow2}{Offer \\ received}{4}{L}
\AddText{yellow2}{Offer \\ signed}{4}{m}
\AddText{yellow3}{File under \\ review}{5}{M}
\AddText[xshift=-3pt]{green1}{Negotiator \\ assigned}{6}{L}
\AddText{green1}{Offer in final \\ review}{6}{m}
\AddText[xshift=3pt]{green2}{Short sale\\ approved}{7}{L}
\AddText{green2}{Under \\ contract}{7}{m}
\AddText[text=white]{green2!60!black}{Vacate \& \\ close}{7}{R}
\end{timeline}

\end{document}

Explanation

  1. I defined an environment timeline and a \TimeLine command to easily produce the timeline; the command takes as mandatory argument a comma separated list in the form

    \TimeLine{<value-1>/<color-1>/<text-1>,...,<value-n>/<color-n>/<text-n>}
    

    For example, by using

    \begin{timeline}
    \TimeLine{%
        1/red1/{},%
        2/red2/{},%
        8/yellow1/{30--60 days},%
        1/yellow2/{},%
        12/yellow3/{30--90 days},%
        4/green1/{10--30 days},%
        6/green2/{30--45 days}%
      }
    \end{timeline}
    

    one gets

    enter image description here

  2. The text boxes are typeset using a node, through an \AddText command with syntax

    \AddText[<options for the node>]{<color>}{<text>}{<position>}{<number>}
    

    where <position> can be l, m, or r (for left, middle, or right, resp.) below the timeline, or L, M, or R (for left, middle, or right, resp.) above the timeline. <number> specifies the number of the part in the timeline which will receive the text. For example, using

    \AddText{red}{text}{l}{5}
    

    will typeset "text" inside a red arrow box to the left of the fifth part of the timeline.

  • Nice code. I was playing with it and could not find where the number of blocks in any color is limited to 19. I tried '30/red1/{},%' to test this. – R. Schumacher Mar 9 '15 at 3:31
  • @R.Schumacher Thanks. The problem you mention is most probably a restriction of rectangle split, although there's a way to overcome this (as far as I recall). I'll check this later and let you know. – Gonzalo Medina Mar 9 '15 at 11:56
  • Great answer, can you help explain what's the purpose to add "\relax" at some lines? – Beatlej Mar 9 '15 at 15:31
  • @Beatlej Thanks. Regarding \relax, see for example tex.stackexchange.com/q/86385/3954. Short answer: it tells TeX to stop scanning. – Gonzalo Medina Mar 9 '15 at 15:37
  • @R.Schumacher In fact, rectangle split only works as expecte up to 20 parts. I thought that using rectangle split allocate boxes one could overcome this but my tests show me that 20 is the maximum for the number of parts for each rectangle. – Gonzalo Medina Mar 9 '15 at 16:02

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.