Crie uma linha do tempo curva em Tex

Crie uma linha do tempo curva em Tex

Estou tentando criar uma linha do tempo que inclua 24 pontos no tempo colocados em uma seta curva da seguinte maneira:

insira a descrição da imagem aqui

Tenho uma versão de seta reta (de @Gonzalo Medina), mas é maior que a largura da página, então quero ter uma linha do tempo curva como acima. Gostaria de pedir sua ajuda. Muito obrigado.

\documentclass[a4]{article}
\usepackage[margin=0cm]{geometry}
\usepackage{ragged2e}
\usepackage{tikz} 
\usetikzlibrary{chains,shapes.arrows,fit,calc}

\definecolor{arrowcolor}{RGB}{50,130,230}
\definecolor{circlecolor}{RGB}{79,129,189}
\colorlet{textcolor}{white}
\colorlet{bordercolor}{white}

\pgfdeclarelayer{background}
\pgfsetlayers{background,main}

\newcounter{task}

\newlength\taskwidth
\newlength\taskvsep

\setlength\taskwidth{2.5cm}
\setlength\taskvsep{17pt}

\def\taskpos{}
\def\taskanchor{}

\newcommand\task[1]{%
  {\parbox[t]{\taskwidth}{\scriptsize\Centering#1}}}

\tikzset{
inner/.style={
  on chain,
  circle,
  inner sep=1pt,
  fill=circlecolor,
  line width=0.5pt,
  draw=bordercolor,
},
on grid
}

\newcommand\Time[2][]{%
\node[inner xsep=0pt] (c1) {\phantom{A}};
\stepcounter{task}
\ifodd\thetask\relax
  \renewcommand\taskpos{\taskvsep}\renewcommand\taskanchor{south}
\else
  \renewcommand\taskpos{-\taskvsep}\renewcommand\taskanchor{north}
\fi
\node[inner,font=\footnotesize\sffamily\color{textcolor}]    
  (c\the\numexpr\value{task}+1\relax) {#1};
\node[anchor=\taskanchor,yshift=\taskpos] 
  at (c\the\numexpr\value{task}+1\relax) {\task{#2}};
}

\newcommand\drawarrow{a
\ifnum\thetask=0\relax
  \node[on chain] (c1) {};
\fi
\node[on chain] (f) {};
\begin{pgfonlayer}{background}
\node[
  inner sep=10pt,
  single arrow,
  single arrow head extend=0.5cm,
  draw=none,
  fill=arrowcolor,
  fit= (c1) (f)
] (arrow) {};
\fill[white] 
  (arrow.before tail) -- (c1|-arrow.east) -- (arrow.after tail) -- cycle;
\end{pgfonlayer}
}

\newenvironment{timeline}[1][node distance=.5\taskwidth]
  {\par\noindent\begin{tikzpicture}[start chain,#1]}
  {\drawarrow\end{tikzpicture}\par}

\begin{document}

\begin{timeline}
\Time[1958]{Task 1}
\Time[1959]{Task 2}
\Time[1960]{Task 3}
\Time[1961]{Task 4}
\Time[1962]{Task 5}
\Time[1963]{Task 6}
\Time[1964]{Task 7}
\Time[1965]{Task 8}
\Time[1966]{Task 9}
\Time[1967]{Task 10}
\Time[1968]{Task 11}
\Time[1969]{Task 12}
\Time[1970]{Task 13}
\Time[1971]{Task 14}
\Time[1972]{Task 15}
\Time[1973]{Task 16}
\Time[1974]{Task 17}
\Time[1975]{Task 18}
\Time[1976]{Task 19}
\Time[1977]{Task 20}
\Time[1978]{Task 21}
\Time[1979]{Task 22}
\Time[1980]{Task 23}
\Time[1981]{Task 24}
\end{timeline}

\end{document}

Ref.:Como posso fazer um cronograma padrão?[adicionado pela comunidade]

Responder1

Para começar...

  • Para uma seta em várias linhas, sugiro usar a arrows.metabiblioteca

     % p.221
     %\usetikzlibrary {arrows.meta}
     \tikz \draw [line width=1ex,
     {Triangle Cap[reversed]-{Latex[length=0pt +2]}}]
     (0,0) -- (1,0);
    
  • Para o rótulo task1, task2... eu uso \node alsowith label distancein\tikzset

EDIT: Com um formato mais arredondado, uso a circle(com a clip) e adiciono 2 argumentos no bar arrow#1 para o início #2 para o final.

  • Eu adiciono um comprimento \arrowvseppara a distância entre as setas

O código

\documentclass[a4paper]{article}
% https://tex.stackexchange.com/questions/715875/create-a-curved-timeline-in-tex
\usepackage[showframe,margin=1cm]{geometry}
\usepackage{tikz} 
\usetikzlibrary{arrows.meta}
\usetikzlibrary {positioning}
\usetikzlibrary {chains}
%  color
\definecolor{arrowcolor}{RGB}{50,130,230}
\definecolor{circlecolor}{RGB}{79,129,189}
\colorlet{textcolor}{white}
\colorlet{bordercolor}{white}
%  length
\newlength\taskwidth
\newlength\taskvsep
\newlength\arrowvsep%<-- added
\setlength\taskwidth{2.cm}
\setlength\taskvsep{1.5ex}
\setlength\arrowvsep{3.cm}
%
\begin{document}
%in th doc p.601
\begin{tikzpicture}[start chain,node distance=5mm]
    % The chain is called just "chain"
    \draw[help lines] (0,-1) grid (2,1);
    \node [on chain] {A};
    \node [on chain] {B};
    \node [on chain] {C};
\end{tikzpicture}

\vspace{1cm}
\begin{tikzpicture}[start chain,node distance=5mm]
    % The chain is called just "chain"
    \draw[help lines] (0,-1) grid (2,1);
    \node [on chain,circle,draw] {A};
    \node [on chain,circle,draw] {B};
    \node [on chain,circle,draw] {C};
\end{tikzpicture}

\vspace{1cm}
%\usetikzlibrary {positioning}
\begin{tikzpicture}[start chain,node distance=1cm,on grid]
    % The chain is called just "chain"
    \draw[help lines] (0,-1) grid (2,1);
    \node [on chain,circle,draw] {A};
    \node [on chain,circle,draw] {B};
    \node [on chain,circle,draw] {C};
\end{tikzpicture}

\vspace{1cm}
\begin{tikzpicture}[start chain=1 going right,
    start chain=2 going left,
    node distance=5mm,
    every node/.style=draw]
    \draw[help lines] (0,-2) grid (3,1);
    \node [on chain=1] {A};
    \node [on chain=1] {B};
    \node [on chain=1] (C){C};
    \node [on chain=2] at ([shift={(0.5cm,-1cm)}]C) {0};
    \node [on chain=2] {1};
    \node [on chain=2] {2};
    \end{tikzpicture}

\vspace{1cm}
        % p.221
        %\usetikzlibrary {arrows.meta}
        \tikz \draw [line width=1cm,
        {Triangle Cap[reversed]-{Latex[length=0pt +2]}}]
        (0,0) -- (5,0);


 \begin{tikzpicture}
    \draw [line width=1cm,
        {Triangle Cap[reversed]-}]
        (0,0) -- (5,0);
        \begin{scope}
            \clip (5,-3) rectangle (6.5,1.5);
            \draw[line width=1cm] (5,-1) circle[radius=1cm]; 
        \end{scope}
    \draw [line width=1cm,
        -{Latex[length=0pt +2]}]
        (5,-2) -- (0,-2);
 \end{tikzpicture}


\tikzset{
    node distance=1.5cm,
    on grid,
    bar height/.initial=1.2cm,
    bar arrow/.style args={#1/#2}%
        {%
            #1-#2,
            arrowcolor,
            line width=\pgfkeysvalueof{/tikz/bar height},
            %rounded corners=5mm
        },
    inner/.style=
        {
            %on chain,
            circle,
            inner sep=1pt,
            minimum width=1cm,
            fill=circlecolor,
            line width=0.5pt,
            draw=bordercolor,
            font=\footnotesize\sffamily\color{textcolor},
        },
    label distance=\taskvsep
}

\vspace{1cm}
\noindent\centering
\fbox{%<--- comment on the final document
    \begin{tikzpicture}
    [%
        trim left=-1.5cm,% begin of the arrow at -1.5
        start chain=1 going right,
        start chain=2 going left,
    ]
    \draw[help lines] (0,0) grid (15,-4);%<-- comment in the final doc
    % \draw[bar arrow] (-1.5,0) -- (15,0) -- ++(0,-\arrowvsep)--(-1.5,-\arrowvsep);
    \draw[bar arrow={Triangle Cap[reversed]/{}}] (-1.5,0) -- (14,0);
    \begin{scope}
        \clip (14,-3.7) rectangle (16.2,1.5);
        \draw[bar arrow={{}/{}}] (14,-0.5\arrowvsep) circle[radius=0.5\arrowvsep]; 
    \end{scope}
    \draw[bar arrow={{}/{{Latex[arrowcolor, length=0pt +2]}}}] (14,-\arrowvsep) -- (-0.5\arrowvsep,-\arrowvsep);
    
    \foreach \i/\d in{
        1/1958,
        2/1958,
        3/1960,
        4/1961,
        5/1962,
        6/1963,
        7/1964,
        8/1965,
        9/1966,
        10/1967}
        {
            \node[inner,on chain=1] (N_\i)  {\d};
            \node also [label=\ifodd\i above\else below\fi:task\i] (N_\i);
        }
    \node [on chain=2] at ([shift={(1cm,-\arrowvsep)}]N_10) {};
    \foreach \i in{11,...,19}
        {
            \node[inner,on chain=2] (N_\i) {Date\i};
            \node also [label=\ifodd\i below\else above\fi:task\i] (N_\i);
        }
    \end{tikzpicture}%
}
\end{document}

insira a descrição da imagem aqui

Responder2

Gostei deste tipo de gráfico e vi que se prestava às soluções que tenho para impressão de etiquetas massivas, o caminho é traçado por partes começando da cauda em direção à cabeça, quando o number of sectionsconsecutivo atinge um valor específico, a respectiva curva é desenhada e as seções são desenhadas no sentido oposto, após completar o dobro do valor do número de seções, a outra curva é desenhada e o contador é zerado, fazendo assim o caminho crescer automaticamente, parando finalmente o cabeçote que era necessário condicionar os desenhos para a entrada de dados de texto, que ao invés de desenhar o corpo desenha a cabeça quando o texto está ende nesse caso tem 2 opções se vai ou volta, se está retornando Você deve colocar reverse, para que desenhe o seguir na direção oposta, aprendi muito fazendo isso, tirando coisas daqui e dali, por isso compartilho e por causa do fim de semana em casa.

Faço esse tipo de organização de código porque os dados podem ser ordenados em linhas, e no caso de gerar etiquetas posso obtê-los rapidamente utilizando uma planilha de dados como Excel, por exemplo, exportando seu respectivo formato de código tikz em uma caixa final.

Mandei completar alguns dos textos com um chatbot com determinados temas, espero que não sejam incômodos.

RESULTADO: insira a descrição da imagem aqui

MWE:

\documentclass[tikz,border=1cm]{standalone}
\usepackage{ifthen}
\usepackage{helvet}
\definecolor{arrowcolor}{RGB}{50,130,230}

\begin{document}
    \def\NTsize{\sf\bfseries\normalsize}
    \def\CTsize{\sf\bfseries\normalsize}
    
    \def\BODY#1#2#3#4#5#6#7#8#9{
        \begin{scope}[shift={(#1)},rotate=0,transform shape]
            \ifthenelse{\equal{#2}{end}}{%Draw The end Arrow Head
                \ifthenelse{\equal{#3}{reverse}}{
                    \filldraw[#6]%Reversed Arrow
                        (-1pt,#5*0.5+#7/2)
                            -- ++(#4*0.5+1pt,0)
                            -- ++ (0,3mm) 
                            -- (#4,#5*0.5)
                            -- (#4*0.5,#5*0.5-#7/2-3mm)
                            -- ++(0,3mm)
                            -- ++(-#4*0.5-1pt,0);
                    }{
                    \filldraw[#6]%Normal Arrow
                        (#4+1pt,#5*0.5+#7/2)
                            -- ++(-#4*0.5-1pt,0)
                            -- ++ (0,3mm)
                            -- (0,#5*0.5)
                            -- (#4*0.5,#5*0.5-#7/2-3mm)
                            -- ++(0,3mm)
                            -- ++(#4*0.5+1pt,0);
                }
            }{% Draw the normal body
                \filldraw[#6] (0,#5*0.5+#7/2) rectangle ++(#4,-#7);
                \draw[white](#4*0.5,#5*0.5) node[circle,draw,fill=#6!70!black, minimum size=#7-3mm,font=\NTsize](temp){#2};
                \draw(temp)+(#8:#9) node[text width=#4-3mm, align=center,font=\CTsize](t2){#3};
                \draw[#6!40!white, preaction={draw,#6, line width=2pt}](temp)--(t2);
            }               
        \end{scope} 
    }

    \def\TAIL#1#2#3#4#5{
        \begin{scope}[shift={(#1)}]
            \filldraw[#4] (#2+1pt,#3*0.5+#5/2)-- ++(-#2*0.5-1pt,0) -- (#2*0.75,#3*0.5) -- (#2*0.5,#3*0.5-#5/2) -- ++ (1pt+#2*0.5,0);
        \end{scope} 
    }
    
    \def\CURVE#1#2#3#4#5#6{
        \begin{scope}[shift={(#1)},#4,transform shape]
            \filldraw[#5](-1pt,#3*0.5-#6/2) -- ++(1pt,0) arc (90:-90:#3*0.5-#6/2) -- ++(-1pt,0)-- ++(0,-#6) -- ++(1pt,0) arc (-90:90:#3/2+#6/2)--++(-1pt,0);
        \end{scope} 
    }
    
    \def\SNAKETEXT#1(#2)[#3][#4][#5]#6#7{%\SNAKETEXT{Contents}(Position)[x_dim][y_dim][colour]{tasks_per_line}{arrow size}
        \begin{scope}[shift={(#2)}]
            \edef\Shiftx{0}
            \edef\Shifty{0}
            \pgfmathparse{int(#6*2)}
            \xdef\tpl{\pgfmathresult}
            \foreach \cod/\direc/\dist/\desc [count=\ctr from 0] in {#1}{
                \ifnum\ctr=0
                    \TAIL{\Shiftx*#3,-\Shifty*#4-#4}{#3}{#4}{#5}{#7}
                \fi
                \ifnum\ctr<#6
                    \pgfmathparse{int(\Shiftx+1)}
                    \xdef\Shiftx{\pgfmathresult}
                    \BODY{\Shiftx*#3,-\Shifty*#4-#4}{\cod}{\desc}{#3}{#4}{#5}{#7}{\direc}{\dist}
                \fi
                \ifnum\ctr=#6
                    \pgfmathparse{int(\Shiftx+1)}
                    \xdef\Shiftx{\pgfmathresult}
                    \CURVE{\Shiftx*#3,-\Shifty*#4-#4}{#3}{#4}{}{#5}{#7}
                    \pgfmathparse{int(\Shiftx-1)}
                    \xdef\Shiftx{\pgfmathresult}
                    \pgfmathparse{int(\Shifty+1)}
                    \xdef\Shifty{\pgfmathresult}
                    \BODY{\Shiftx*#3,-\Shifty*#4-#4}{\cod}{\desc}{#3}{#4}{#5}{#7}{\direc}{\dist}
                \fi
                \ifnum\ctr>#6
                    \ifnum\ctr<\tpl
                        \pgfmathparse{int(\Shiftx-1)}
                        \xdef\Shiftx{\pgfmathresult} 
                        \BODY{\Shiftx*#3,-\Shifty*#4-#4}{\cod}{\desc}{#3}{#4}{#5}{#7}{\direc}{\dist}
                    \fi
                \fi
                \ifnum\ctr=\tpl
                    \pgfmathparse{int(\Shiftx-1)}
                    \xdef\Shiftx{\pgfmathresult}
                    \CURVE{\Shiftx*#3+#3,-\Shifty*#4-#4}{#3}{#4}{xscale=-1}{#5}{#7}
                    \pgfmathparse{int(\Shifty+1)}
                    \xdef\Shifty{\pgfmathresult}
                    \pgfmathparse{int(\Shiftx+1)}
                    \xdef\Shiftx{\pgfmathresult}
                    \BODY{\Shiftx*#3,-\Shifty*#4-#4}{\cod}{\desc}{#3}{#4}{#5}{#7}{\direc}{\dist}
                    \xdef\ctr{0}
                \fi
            }
        \end{scope} 
    }
    
    \begin{tikzpicture}
        \SNAKETEXT{
            task1/90/20mm/Detail of task 1,
            task2/-90/20mm/Detail of task 2,
            task3/90/20mm/Detail of task 3,
            task4/-90/20mm/Detail of task 4,
            task5/90/23mm/Some manual text input for more details,
            task6/-90/23mm/Become a Professional Procrastinator,
            task7/90/20mm/Organize Your Clutter,
            task8/-90/20mm/Master the Art of Napping,
            task9/90/20mm/Attend a Productivity Seminar,
            task10/-90/23mm/Create a To-Do List for Doing Nothing,
            task11/-90/20mm/Practice Active Inactivity,
            task12/90/20mm/Become an Expert at Waiting,
            task13/-90/20mm/Write a Book on Doing Nothing,
            task14/90/20mm/Achieving Zen in Pajamas,
            task15/-90/20mm/Watch 10 Hours of Cat Videos,
            task16/90/23mm/Reorganized My Sock Drawer Instead of Studying,
            task17/-90/30mm/Dedicate hours each day to scrolling through social media feeds.,
            task18/90/25mm/Spend hours contemplating the meaning of life,
            task19/-90/20mm/Some task like doing nothing,
            end/end/end/end%
        }(0,0)[25mm][50mm][arrowcolor]{10}{20mm}
    
        %Changing the font sizes
        \def\NTsize{\sf\bfseries\scriptsize}
        \def\CTsize{\sf\bfseries\scriptsize}
        \SNAKETEXT{
            JAN-30/-90/15mm/Polar Bear Plunge Day,
            FEB-29/90/15mm/International Lost Sock Memorial Day,
            MAR-13/-90/15mm/Global Labyrinth Day,
            APR-30/90/15mm/National Awkward Silence Appreciation Day,
            MAY-15/-90/15mm/World Emoji Day,
            JUN-07/-90/15mm/National Talk Like a Pirate Day,
            JUL-15/90/15mm/Global Prohibition Day,
            AUG-12/-90/15mm/National Overthinking Awareness Weeky,
            SEP-06/90/15mm/World Couch Potato Championship,
            OCT-17/-90/15mm/National Socks-with-Sandals Day,
            NOV-28/-90/15mm/ Global Pajama Conference,
            DEC-25/90/15mm/World Simultaneous Eye Roll Day ,
            end/end/end/reverse%
        }(0,-13)[25mm][30mm][green!50!black]{5}{15mm}
    
        %Changing the font sizes
        \def\NTsize{\sf\bfseries\tiny}
        \def\CTsize{\sf\bfseries\tiny}
        \SNAKETEXT{
            A/90/5mm/cmt-stg1,
            B/90/5mm/cmt-stg2,
            C/90/5mm/cmt-stg3
            D/90/5mm/cmt-stg4,
            E/90/5mm/cmt-stg5,
            F/90/5mm/cmt-stg6,
            G/90/5mm/cmt-stg7,
            H/90/5mm/cmt-stg8,
            I/90/5mm/cmt-stg9,
            J/90/5mm/cmt-stg10,
            K/90/5mm/cmt-stg11,
            L/90/5mm/cmt-stg12,
            M/90/5mm/cmt-stg13,
            N/90/5mm/cmt-stg14,
            M/90/5mm/cmt-stg15,
            O/90/5mm/cmt-stg16,
            end/end/end/end%
        }(18,-11)[20mm][10mm][cyan!50!green]{2}{5mm}
    
        %Changing the font sizes
        \def\NTsize{\sf\bfseries\tiny}
        \def\CTsize{\sf\bfseries\tiny}
        \SNAKETEXT{
            A/90/5mm/cmt-stg1,
            B/90/5mm/cmt-stg2,
            C/90/5mm/cmt-stg3
            D/90/5mm/cmt-stg4,
            E/90/5mm/cmt-stg5,
            F/90/5mm/cmt-stg6,
            G/90/5mm/cmt-stg7,
            H/90/5mm/cmt-stg8,
            I/90/5mm/cmt-stg9,
            J/90/5mm/cmt-stg10,
            K/90/5mm/cmt-stg11,
            L/90/5mm/cmt-stg12,
            M/90/5mm/cmt-stg13,
            N/90/5mm/cmt-stg14,
            M/90/5mm/cmt-stg15,
            O/90/5mm/cmt-stg16,
            P/90/5mm/cmt-stg17,
            Q/90/5mm/cmt-stg18,
            end/end/end/reverse%
        }(24,-11)[20mm][10mm][red!50!blue]{2}{5mm}
    \end{tikzpicture}
\end{document}

informação relacionada