10

I would like to add several labels to a plot in pgfplots: one label for the month and one for the year, just like in this graph:

enter image description here

I tried to use the extra tick label, but I don't know how it is possible to change its format from month to year, so the extra and normal x label have the same format. Also I could not figure out how to get the ticks shifted so that they are left and right of the month label instead of centered.

MWE

\documentclass{article}

\usepackage{pgfplots}
\usepgfplotslibrary{dateplot} 

\begin{document}

\begin{tikzpicture}
\begin{axis}[
date coordinates in=x,
xtick=data,
extra x ticks={2009-10-01, 2010-02-01},
extra x tick style={yshift=-20pt},
%extra xticklabel=\year, % does not work
xticklabel style={anchor=near xticklabel},
xticklabel=\month,
date ZERO=2009-08-01,% <- improves precision!
]
\addplot coordinates {
(2009-08-01, 050)
(2009-09-01, 100)
(2009-10-01, 100)
(2009-11-01, 100)
(2009-12-01, 040)
(2010-01-01, 020)
(2010-02-01, 000)
(2010-03-01, 035)
};
\end{axis}
\end{tikzpicture}

\end{document}

EDIT

In order to get vertical lines between the different months labels, I tried to use Jakes approach and tried to name the nodes \year\month, e.g. 20102 (2010 Feb). The problem with that is that the months (\month) contain leading zeros and the parser parses them as octal numbers. So when I try to calculate \month-1 to get the node before the current one, I receive a parser error. In order to solve that I tried to use the methods provided here, but none of them worked so far.

MWE2

\documentclass[border=5mm]{standalone}

\usepackage{pgfplots}
\usepgfplotslibrary{dateplot} 
\usetikzlibrary{calc}

\makeatletter
\long\def\ifnodedefined#1#2#3{%
    \@ifundefined{pgf@sh@ns@#1}{#3}{#2}%
}
\makeatother

\begin{document}

\def\monthnames{{1,2,3,4,5,6,7,8,9,10,11,12}}

\begin{tikzpicture}
\begin{axis}[
date coordinates in=x,
xtick=data,
xticklabel style={
    anchor=near xticklabel,     
        % Approach 1: Does not work missing endcsname error
    %name=\ifnodedefined{start\year{\pgfcalendar{tickcal}{\tick}{\tick}{\pgfcalendarshorthand{m}{-}}}} 
        %{end\year}  % Then this could be the last month
        %{start\year}, % Otherwise, start the year      
        % Approach 2: Does not work missing endcsname error
    %name=\ifnodedefined{start\year\pgfmathparse{\monthnames[Mod(\tick-1,12)]}\pgfmathresult} % Does not work missing endcsname error
        %{end\year}  % Then this could be the last month
        %{start\year}, % Otherwise, start the year      
},
xticklabel=\month,
date ZERO=2009-08-01,% <- improves precision!
]
\addplot coordinates {
(2009-08-01, 050)
(2009-09-01, 100)
(2009-10-01, 100)
(2009-11-01, 100)
(2009-12-01, 040)
(2010-01-01, 020)
(2010-02-01, 000)
(2010-03-01, 035)
};
\end{axis}
\end{tikzpicture}

\end{document}
8

You almost had it: The extra tick labels can accept all the same options as the normal tick labels, you just need to provide them via extra x tick style={<normal tick options>}. In this case, you would say extra x tick style={xticklabel=\year}.

If you want to fancy things up a little bit, you can draw the group lines automatically, using a bit of trickery with naming the label nodes and checking for the existence of named nodes using the approach from Checking whether or not a node has been previously defined:

\documentclass{standalone}

\usepackage{pgfplots}
\usepgfplotslibrary{dateplot} 

\makeatletter
\long\def\ifnodedefined#1#2#3{%
    \@ifundefined{pgf@sh@ns@#1}{#3}{#2}%
}
\makeatother

\begin{document}

\begin{tikzpicture}
\begin{axis}[
date coordinates in=x,
xtick=data,
extra x ticks={2009-10-01, 2010-02-01},
extra x tick style={
    yshift=-3.5ex,
    xticklabel=\year,
    xticklabel style={name={}},
    major tick length=0pt
},
xticklabel style={
    anchor=near xticklabel,
    name=\ifnodedefined{start\year} % Have we already started this year?
        {end\year}  % Then this could be the last month
        {start\year}, % Otherwise, start the year
    append after command=
        \pgfextra{\pgfmathtruncatemacro\lastyear{\year-1}}
        \ifnodedefined{end\lastyear}
        {
                {\ifnum\month=1 (start\lastyear.south west) edge (end\lastyear.south east) \pgfextra{\xdef\finalyear{\year}}\fi}}
        {}
},
after end axis/.code={
    \draw (start\finalyear.south west) -- (end\finalyear.south east);
},
xticklabel=\month,
date ZERO=2009-08-01,% <- improves precision!
]
\addplot coordinates {
(2009-08-01, 050)
(2009-09-01, 100)
(2009-10-01, 100)
(2009-11-01, 100)
(2009-12-01, 040)
(2010-01-01, 020)
(2010-02-01, 000)
(2010-03-01, 035)
};
\end{axis}
\end{tikzpicture}

\end{document}

Or, similarly, if you want vertical separating lines between the years:

\documentclass[border=5mm]{standalone}

\usepackage{pgfplots}
\usepgfplotslibrary{dateplot} 
\usetikzlibrary{calc}

\makeatletter
\long\def\ifnodedefined#1#2#3{%
    \@ifundefined{pgf@sh@ns@#1}{#3}{#2}%
}
\makeatother

\begin{document}

\begin{tikzpicture}
\begin{axis}[
date coordinates in=x,
xtick=data,
tick pos=left,
yticklabel style={append after command={(\tikzlastnode.east) edge +(0.15cm,0)}},
major tick length=0pt,
extra x ticks={2009-10-01, 2010-02-01},
extra x tick style={
    yshift=-3.5ex,
    xticklabel=\year,
    xticklabel style={name={}},
    every x tick label/.style={}
},
xticklabel style={
    anchor=near xticklabel,
    alias=tick\ticknum,
    name=\ifnodedefined{start\year} % Have we already started this year?
        {end\year}  % Then this could be the last month
        {start\year}, % Otherwise, start the year
    append after command=
        \pgfextra{\pgfmathtruncatemacro\lastyear{\year-1}}
        \ifnodedefined{end\lastyear}
        {
                {\ifnum\month=1 ({$(end\lastyear.south west)!0.5!(start\year.south east)$}|-{rel axis cs:0,0}) edge ++(0,-7ex)
                \fi}
        }
        {}
        \ifnum\ticknum>0
                \ifnum\month>1
                    \pgfextra{\pgfmathtruncatemacro\prevticknum{\ticknum-1}}
        ($(tick\prevticknum.north east)!0.5!(tick\ticknum.north west)$) edge ++({0,-3ex})
                \fi
        \fi
},
after end axis/.code={
    \draw (rel axis cs:0,0) -- ++(0,-7ex)
            (rel axis cs:1,0) -- ++(0,-7ex);
},
xticklabel=\month,
date ZERO=2009-08-01,% <- improves precision!
]
\addplot coordinates {
(2009-08-01, 050)
(2009-09-01, 100)
(2009-10-01, 100)
(2009-11-01, 100)
(2009-12-01, 040)
(2010-01-01, 020)
(2010-02-01, 000)
(2010-03-01, 035)
};
\end{axis}
\end{tikzpicture}

\end{document}
  • thanks for your help. You seem to know everything about pgfplots! I think it might look better, if the lines are vertical like in the example graph. I wanted to take a look into that later. – maetra Jun 21 '13 at 14:30
  • @maetra: I've edited my answer to show how you can get vertical separating lines. – Jake Jun 21 '13 at 14:40
  • great work, imho vertical lines for the month labels would make look even better – maetra Jun 21 '13 at 14:55
  • I tried to get the vertical lines for the months too, but with \pgfextra{\pgfmathtruncatemacro\lastmonth{\month-1}} I get a pgfmatherror since the month labels are written as '08' instead of '8'. Do you know how to solve that? – maetra Jun 24 '13 at 10:01
  • @maetra: You could use \numexpr to do the calculations instead of \pgfmathparse, or you could use the \ticknum macro instead, which contains the current tick number. I've used the second method in my edited answer. – Jake Jun 25 '13 at 15:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.