Plotando dados de série temporal

Plotando dados de série temporal

Gostaria de traçar séries temporais trimestrais com recursos especiais do eixo x. Em particular, gostaria de ver marcas pequenas indicando quando os trimestres começam e marcas maiores indicando quando os anos começam, mas gostaria apenas de rotular os anos (e não os trimestres). Para fins de ilustração, o exemplo a seguir faz exatamente o que desejo, exceto que o código não é nada flexível.

\documentclass{article}   
\usepackage{pgfplots}   
\usepackage{filecontents}
\pgfplotsset{width=8cm,compat=newest}   
\usepgfplotslibrary{dateplot}     

\usetikzlibrary{calc}

\begin{filecontents}{Quarterly.dat}
date    Y
2009-02-15  1
2009-05-15  2
2009-08-15  3
2009-11-15  4
2010-02-15  4
2010-05-15  4
2010-08-15  4
2010-11-15  4
2011-02-15  4
2011-05-15  4
2011-08-15  4
2011-11-15  4
2012-02-15  4
2012-05-15  4
2012-08-15  4
2012-11-15  4
2013-02-15  4
2013-05-15  4
2013-08-15  4
2013-11-15  4
\end{filecontents}

\begin{document}
\begin{tikzpicture}
\begin{axis}[
mark =none,
xmin=2008-12-01,
xmax=2012-02-01,
major tick length=4pt,
minor tick length=2pt,
date coordinates in=x,
minor x tick num=3,
xtick={2009-01-01,2010-01-01,2011-01-01,2012-01-01}, 
xticklabels= {\year,\year,\year},
x tick label style={anchor=east,xshift=1.5cm,yshift=-0.3cm},
]
\addplot [only marks,green]table [x=date,y=Y]{Quarterly.dat}; %
\end{axis}
\end{tikzpicture}
\end{document} 

O código não é flexível por vários motivos. Por exemplo, se eu escrever xtick={2009-01-01,2010-01-01,2011-01-01,2012-01-01,2013-01-01}, ele minor x tick num=3para de funcionar (provavelmente porque os ticks não têm a mesma distância). O exemplo também exige que eu configure manualmente xshift(no exemplo xshift=1.5cm). Seria ótimo se o código pudesse rotular automaticamente todos os anos para qualquer série temporal trimestral. Também tentei usar a opção extra x ticks, mas sem sucesso.

captura de tela

Responder1

Acontece que esta é uma prática muito boa para x coord trafo/.codee x coord inv trafo/.code. Antes disso, deixe-me explicar um pouco.

Seu problema se divide nas três partes a seguir:

  • Primeiro, os principais ticks devem aparecer a cada véspera de ano novo. Mas dateplotnão sabe nada sobre o ano novo.
  • Em segundo lugar, os ticks menores aparecem apenas se os ticks maiores forem separados uniformemente. Mas os anos duram 365 ou 366 dias.
  • Terceiro, você deseja controlar o layout.

Existe uma maneira muito fácil de superar isso: tornar os anos tão largos quanto os outros. Mais precisamente, uso 2015.09314 para representar hoje, 3 de fevereiro de 2015. Isso muda tudo porque:

  • As vésperas de ano novo agora são representadas por números inteiros epgfplots O AMOR Éinteiro.
  • Os anos têm uma unidade de comprimento.
  • Controlar o layout é mais fácil com algo como xmin=2008.

Então tudo que você precisa fazer é verificar tikzlibrarypgfplots.dateplot.code.texe escrever o seu próprio arquivo year coordinates in. No código a seguir, /pgfplots/#1 coord trafoé usado para transformar sua entrada 2015-2-3em um número decimal 2015.09314para que você pgfplotspossa plotar os dados. Por outro lado, x coord inv trafoé utilizado para transformar o número decimal em um texto de etiqueta. (Por exemplo, MMXVem vez de 2015.) (Eu não fiz isso porque o padrão é bom o suficiente.) (Bem... eu configurei 1000 sepnada em outra sintaxe.)

\documentclass[border=1cm]{standalone}
\usepackage{pgfplots}
    \usepgfplotslibrary{dateplot}
\begin{filecontents}{\jobname-Quarterly.dat}
date Y
2009-01-01 9
2009-12-31 9
2010-01-01 0
2010-12-31 0
2014-01-01 4
2014-12-31 4
\end{filecontents}

\makeatletter
\pgfplotsset{
    /pgfplots/year coordinates in/.code={
        \pgfkeysalso{%
            #1 tick label style={/pgf/number format/1000 sep=}, % "2015" rather than "2,015"
            #1 tick label as interval,
            minor #1 tick num=11 % January, ..., December
        }
        \pgfkeysdef{/pgfplots/#1 coord trafo}{
            \begingroup
            \edef\pgfplotstempjuliandate{##1}
            % check if we also have a TIME like '2006-01-01 11:21'
            \expandafter\pgfutil@in@\expandafter:\expandafter{\pgfplotstempjuliandate}
            \ifpgfutil@in@
                % we have a TIME!
                \expandafter\pgfplotslibdateplot@map@time\pgfplotstempjuliandate:\dateto\pgfplotstempjuliandate\timeto\pgfplotstemptime
            \else
                \let\pgfplotstemptime=\pgfutil@empty
            \fi
            \expandafter\pgfcalendardatetojulian\expandafter{\pgfplotstempjuliandate}\c@pgf@counta
            \expandafter\pgfcalendardatetojulian\expandafter{\year-1-0}\c@pgf@countb
            \expandafter\pgfcalendardatetojulian\expandafter{\year-12-31}\c@pgf@countc
            \advance\c@pgf@counta by-\c@pgf@countb % now a = #days from 1/1 to temp
            \advance\c@pgf@countc by-\c@pgf@countb % now b = #days of that year
            \ifx\pgfplotstemptime\pgfutil@empty
                % no time:
                \pgfmathparse{\year+\the\c@pgf@counta/\the\c@pgf@countc}
            \else
                % add time fraction (which should be in the range
                % [0,1]).
                \ifdim\pgfplotstemptime pt<1pt
                    % discard prefix '0.':
                    \expandafter\pgfplotslibdateplot@discard@zero@dot\pgfplotstemptime\to\pgfplotstemptime
                    \pgfmathparse{\year+(\the\c@pgf@counta.\pgfplotstemptime)/\the\c@pgf@countc}%
                \else
                    % assume \pgfplotstemptime=1pt :
                    \advance\c@pgf@counta by1
                    \pgfmathparse{\year+\the\c@pgf@counta/\the\c@pgf@countc}
                \fi
            \fi
            \pgfmath@smuggleone\pgfmathresult
            \endgroup
        }
    }
}

\begin{document}
    \begin{tikzpicture}
        \begin{axis}[year coordinates in=x,minor x tick num=1]
            \addplot [only marks]table[x=date,y=Y]{\jobname-Quarterly.dat};
        \end{axis}
    \end{tikzpicture}
\end{document}

informação relacionada