Построение графиков временных рядов данных

Построение графиков временных рядов данных

Я хотел бы построить квартальный временной ряд со специальными функциями оси x. В частности, я хотел бы видеть маленькие отметки, указывающие начало кварталов, и большие отметки, указывающие начало годов, но хотел бы только помечать годы (а не кварталы). Для наглядности следующий пример делает именно то, что мне нужно, за исключением того, что код совсем не гибкий.

\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} 

Код не является гибким по нескольким причинам. Например, если я напишу xtick={2009-01-01,2010-01-01,2011-01-01,2012-01-01,2013-01-01}, то minor x tick num=3перестанет работать (вероятно, потому что тики не имеют одинакового расстояния). Пример также требует, чтобы я вручную устанавливал xshift(в примере xshift=1.5cm). Было бы здорово, если бы код мог автоматически маркировать все годы для любого квартального временного ряда. Я также пытался использовать опцию дополнительных тиков x, но безуспешно.

скриншот

решение1

Оказывается, это очень хорошая практика для x coord trafo/.codeи x coord inv trafo/.code. Перед этим позвольте мне немного объяснить.

Ваша проблема делится на следующие три части:

  • Во-первых, крупные клещи должны появляться в канун каждого нового года. Но dateplotничего не знают о новом году.
  • Во-вторых, второстепенные тики появляются только в том случае, если основные тики разделены равномерно. Но годы длятся 365 или 366 дней.
  • В-третьих, вы хотите контролировать макет.

Есть очень простой способ обойти это: сделать годы такими же широкими, как и друг у друга. Точнее, я использую 2015.09314 для представления сегодняшнего дня, 3 февраля 2015 года. Это меняет все, потому что:

  • Кануны Нового года теперь представлены целыми числами иpgfplots ЛЮБИТцелое число.
  • Годы имеют длину одной единицы.
  • Управлять макетом проще с помощью чего-то вроде xmin=2008.

Итак, все, что вам нужно сделать, это проверить tikzlibrarypgfplots.dateplot.code.texи написать свой собственный year coordinates in. В следующем коде /pgfplots/#1 coord trafoиспользуется для преобразования вашего ввода 2015-2-3в десятичное число 2015.09314, чтобы затем pgfplotsможно было построить данные. С другой стороны, x coord inv trafoиспользуется для преобразования десятичного числа в текст метки. (Например, MMXVвместо 2015.) (Я не делал этого, потому что значение по умолчанию достаточно хорошее.) (Ну... я установил 1000 sepзначение nothing в другом синтаксисе.)

\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}

Связанный контент