Ich möchte vierteljährliche Zeitreihen mit speziellen X-Achsen-Funktionen darstellen. Insbesondere möchte ich kleine Markierungen sehen, die anzeigen, wann die Quartale beginnen, und größere Markierungen, die anzeigen, wann die Jahre beginnen, möchte aber nur die Jahre (und nicht die Quartale) beschriften. Zur Veranschaulichung macht das folgende Beispiel genau das, was ich möchte, außer dass der Code überhaupt nicht flexibel ist.
\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}
Der Code ist aus mehreren Gründen nicht flexibel. Wenn ich beispielsweise schreibe xtick={2009-01-01,2010-01-01,2011-01-01,2012-01-01,2013-01-01}
, minor x tick num=3
funktioniert das nicht mehr (wahrscheinlich, weil die Ticks nicht den gleichen Abstand haben). Das Beispiel erfordert auch, dass ich manuell einstellen muss xshift
(im Beispiel xshift=1.5cm
). Es wäre toll, wenn der Code alle Jahre für jede vierteljährliche Zeitreihe automatisch beschriften könnte. Ich habe auch versucht, die Option für zusätzliche x Ticks zu verwenden, aber ohne Erfolg.
Antwort1
Es stellt sich heraus, dass dies eine sehr gute Vorgehensweise für x coord trafo/.code
und ist x coord inv trafo/.code
. Lassen Sie mich vorher etwas erklären.
Ihr Problem gliedert sich in die folgenden drei Teile:
- Erstens sollten an jedem Silvester große Häkchen erscheinen. Aber
dateplot
man weiß nichts über Neujahr. - Zweitens erscheinen kleine Teilstriche nur, wenn große Teilstriche gleichmäßig voneinander getrennt sind. Jahre sind jedoch 365 oder 366 Tage lang.
- Drittens möchten Sie das Layout steuern.
Es gibt eine sehr einfache Möglichkeit, das zu umgehen: Machen Sie die Jahre gleich breit. Genauer gesagt verwende ich 2015.09314, um den heutigen Tag, den 3. Februar 2015, darzustellen. Das ändert alles, weil:
- Silvester werden nun durch ganze Zahlen dargestellt und
pgfplots
LIEBTganze Zahl. - Jahre sind eine Einheit lang.
- Die Steuerung des Layouts ist mit etwas wie einfacher
xmin=2008
.
Sie müssen also nur nachsehen tikzlibrarypgfplots.dateplot.code.tex
und Ihr eigenes schreiben year coordinates in
. Im folgenden Code /pgfplots/#1 coord trafo
wird verwendet, um Ihre Eingabe 2015-2-3
in eine Dezimalzahl umzuwandeln 2015.09314
, damit pgfplots
Sie die Daten darstellen können. Andererseits x coord inv trafo
wird verwendet, um die Dezimalzahl in einen Beschriftungstext umzuwandeln. (Zum Beispiel MMXV
anstelle von 2015
.) (Das habe ich nicht gemacht, weil die Vorgabe gut genug ist.) (Nun... ich habe 1000 sep
in einer anderen Syntax nichts eingestellt.)
\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}