Я хотел бы построить квартальный временной ряд со специальными функциями оси 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}