15
$\begingroup$

I need to add custom (vertical) grid lines to a plot (to a DateListPlot, to be precise). I know there is the option of GridLines -> {xgrid, ygrid}. However, this removes the automatic grid lines which I would like to keep.

Is there a simple option to add additional grid lines to the automatic ones? Thank you!


Update: Added a minimal working example.

Take the following DateListPlot

DateListPlot[RandomReal[1, 20], {2000}, Joined -> True]

automatic grid lines

It automatically includes vertical grid lines for each year in grey, which I would like to keep. But let's say I'd like to add a grid line for Guy Fawkes Day 2007, e.g. because I need to later label the event in the plot. I could write

 DateListPlot[RandomReal[1, 20], {2000}, Joined -> True,
              GridLines -> {{"5 Nov 2007"}, None}]

custom grid lines

but this removes the yearly lines. So I was wondering whether it is possible to add the custom grid lines to the automatic ones rather than to overwrite the latter.

Of course, I could manually re-add the annual grid lines, but I hope to avoid this solution because the plots will have different date ranges so I do not always know for which years I'd need to include the lines.

$\endgroup$
  • $\begingroup$ If you add code for a small working example, more people will likely be inclined to help you. $\endgroup$ – Ajasja May 17 '13 at 9:37
  • $\begingroup$ I've included an example. $\endgroup$ – Bernd May 17 '13 at 9:50
  • $\begingroup$ At worst, one could fall back on Epilog and manually add markers for "special" dates (that is, explicitly construct a vertical Line[]). $\endgroup$ – J. M. is away May 17 '13 at 9:55
  • 1
    $\begingroup$ @J.M. Yes, but then I would need to know the y coordinates of the line (i.e. upper and lower bounds), which depends on the range of the data to be plotted. Else, the line will be taller or shorter than the grid itself. $\endgroup$ – Bernd May 17 '13 at 9:58
10
$\begingroup$

Not sure why J.M.'s comment doesn't meet your requirements:

DateListPlot[
 RandomReal[1, 20], {2000},
 Joined -> True,
 PlotRange -> All,
 GridLines -> {Automatic, None},
 Epilog -> {Directive[Thick, Magenta],
   Line[
    {Scaled[{0, -1}, {{2010, 1, 15}, 0}], 
     Scaled[{0, 1}, {{2010, 1, 15}, 0}]
     }]}]

This incorporates Scaled, acknowledging J.M.'s additional comments below as well.

datelist plot


Edit: To add multiple such lines to a graph, the following function takes the dates as arguments and displays them accordingly:

specialdates[dates__] := DateListPlot[
  RandomReal[1, 20], {2000}, Joined -> True, PlotRange -> All,
  Prolog -> {Directive[Orange], Line[
    {Scaled[{0, -1}, {DateString[{#, {"Day", "Month", "Year"}}], 0}],
     Scaled[{0, 1}, {DateString[{#, {"Day", "Month", "Year"}}], 0}]}]
    & /@ {dates}}]

So that

specialdates["05.11.2005", "04.07.2007", "14.07.2011", "12.10.2017"]

yields

multiple dates

$\endgroup$
  • 4
    $\begingroup$ It might be more useful to use Scaled[] for offsetting in the vertical direction. If you use Epilog -> {Directive[Thick, Magenta], Line[{Scaled[{0, -1}, {{2010, 1, 15}, 0}], Scaled[{0, 1}, {{2010, 1, 15}, 0}]}]}, you'll find that even if you change the PlotRange, the vertical magenta line will always hit the horizontal boundaries. $\endgroup$ – J. M. is away May 17 '13 at 10:14
  • $\begingroup$ @J.M. Good plan; I haven't learnt about Scaled yet. (It's the scaling/offset/positioning stuff in Mathematica that still confuses me...) $\endgroup$ – cormullion May 17 '13 at 10:25
  • 3
    $\begingroup$ Here, the notation is not too hard to parse. Scaled[{0, h}, start] corresponds to a scaled vertical offset from the point start; positive values of h go up, and negative values of h go down. h == -1 is the bottommost position, and h == 1 is the topmost. The situation is similar for horizontal offsetting, with Scaled[{h, 0}, start]. $\endgroup$ – J. M. is away May 17 '13 at 10:48
  • $\begingroup$ Ok, the combination of Epilog and Scaled indeed seems to be the most reasonable solution. Thank you all! $\endgroup$ – Bernd May 17 '13 at 11:26
  • 1
    $\begingroup$ @Bernd Actually it should probably be Prolog instead of Epilog $\endgroup$ – Ajasja May 17 '13 at 13:02
6
$\begingroup$

You are asking:

Is there a simple option to add additional grid lines to the automatic ones? Thank you!

Well, I couldn't think of one, but out of curiosity I tried another approach (different to the Epilog I'd also rather choose). It seems to work pretty ok, so I figured I might share. As the other answer is much more versatile, I didn't spend too much time tidying up my code, if you are interested in more details let me know.

Consider the DateListPlot you mentioned:

dlp = DateListPlot[RandomReal[1, 20], {2000}, Joined -> True, 
      GridLines -> {Automatic, None}];

Now, the idea is to just add the desired additional gridlines to dlp directly. Using dlp//FullForm we can easily identify the GridLines and can thus set up the following ReplacemeAll:

addVertGridLine[plot_,dates_List] := 
   (plot /. 
    # -> 
       Insert[#, 
        Unevaluated[
        Sequence @@ ({AbsoluteTime[#[[1]]], #[[2]]} & /@ dates)], {2,1,-1}]) &@
    Cases[plot, x_Rule /; x[[1]] == GridLines, Infinity][[1]]

in words: I use Cases to find the GridLines and then I insert the (unevaluated) Sequence of dates in that list, at the right spot (using AbsoluteTime to make it a bit more user friendly). The setup expects the user to enter a list of date/style lists (in order to make it possible to add many gridlines in one go).

An example will certainly help:

We start with an initial plot:

dlp = DateListPlot[RandomReal[1, 20], {2000}, Joined -> True, GridLines -> {Automatic, None}]

enter image description here

and let's add few Guy Fawkes days:

addVertGridLine[dlp, 
   {{"5 Nov 2005", Directive[Red, Thick]},
    {"5 Nov 2008", GrayLevel[0.8`]}
    {"5 Nov 2012", Directive[Blue, Dashed]}, 
    {"5 Nov 2014", Green}}]

showing various formatting.

I hope this helps.

enter image description here

$\endgroup$
2
$\begingroup$

System`DateListPlotDump`DateTicks

If we could identify how the automatic GridLines are determined it would be straightforward to add the custom grid lines to the automatic ones. It seems that we can replicate the automatically generated major date ticks and hence associated grid lines using the function System`DateListPlotDump`DateTicks in version 11 (and Graphics`DateListPlotDump`DateTicks in version 9).

This function takes two arguments with a third optional argument:

System`DateListPlotDump`DateTicks[arg1: {mindate, maxdate}, ndivisons, labelformat]

and returns a list of (no more than ndivisions) "nice" date divisions in the range from mindate to maxdate with each tick labeled based on labelformat.

For example,

System`DateListPlotDump`DateTicks[{{2010, 1}, {2011, 3}}, 5]

{{3.47129*10^9, "Jan"}, {3.47907*10^9, "Apr"}, {3.48693*10^9, "Jul"}, {3.49488*10^9, "Oct"}, {3.50283*10^9, "Jan"}, {3.5106*10^9, "Apr"}}

The optional third argument allows formatting of date labels:

System`DateListPlotDump`DateTicks[{{2000}, {2018}}, 5, {"Year", "/", "Month"}]

{{3.15567*10^9, "2000/01"}, {3.31353*10^9, "2005/01"}, {3.47129*10^9, "2010/01"}, {3.62906*10^9, "2015/01"}, {3.78683*10^9, "2020/01"}}

The first column of the output gives the automatic grid lines on the date axis. We can append to this list additional grid lines as desired. We can replicate the major ticks on the date axis using the function

System`DateListPlotDump`DateTicks[{##}, 5, "Year"]&

in the option setting for FrameTicks or Ticks.

Examples:

DateListPlot[RandomReal[1, 52], {2000}, Joined -> True, 
 GridLines -> {(Join[System`DateListPlotDump`DateTicks[{#, #2}, 5, "Year"][[All, 1]], 
 {{AbsoluteTime["5 Nov 2007"], Directive[Red, Thick]},
  {AbsoluteTime["5 Mar 2022"], Directive[Blue, Thickness[.007], DotDashed]}}] &), None}]

enter image description here

DateListPlot[RandomReal[1, 60], {2000, 1}, Joined -> True, 
 GridLines -> {(Join[System`DateListPlotDump`DateTicks[{#, #2}, 5, "Year"][[All, 1]], 
 {{AbsoluteTime["5 Nov 2001"], Directive[Red, Thick]}, 
  {AbsoluteTime["5 Mar 2003"], Directive[Blue, Thickness[.007], DotDashed]}}] &), None}]

enter image description here

DateListPlot[MeanFilter[RandomReal[1, 500], 50], {2001, 5, 1}, 
 Joined -> True, GridLinesStyle -> Green, 
 GridLines -> {(Join[System`DateListPlotDump`DateTicks[{#, #2}, 5, "Month"][[All, 1]], 
   {{AbsoluteTime["5 Nov 2001"], Directive[Red, Thick]}, 
    {AbsoluteTime["5 Mar 2002"], Directive[Blue, Thickness[.007], DotDashed]}}] &), None}]

enter image description here

Post-process

Alternatively, extract the grid lines from DateListPlot output with automatic GridLines and use the modified list of grid lines in Show.

dlp = DateListPlot[RandomReal[1, 60], {2000, 1}, Joined -> True, 
  GridLines -> {Automatic, None}];
newlines = {{AbsoluteTime["5 Nov 2001"], Directive[Red, Thick]}, 
  {AbsoluteTime["5 Mar 2003"], Directive[Blue, Thickness[.007], DotDashed]}};
Show[dlp, GridLines -> {Join[First[GridLines /. dlp[[2]]], newlines], 
   Last[GridLines /. dlp[[2]]]}]

enter image description here

$\endgroup$
1
$\begingroup$

You could avoid using internal functions and instead use AbsoluteOptions to obtain the GridLines that are used by default, and then augment them as desired. To do this you will probably need to use the workaround presented in my answer to question (68937). Then:

plot = DateListPlot[
    RandomReal[1,20],
    {2000},
    GridLines->{Automatic,None},
    Joined->True
];

gridlines = OptionValue[
    AbsoluteOptions @ plot,
    GridLines
]

{{{3.15567*10^9, {GrayLevel[0.], AbsoluteThickness[0.25]}}, {3.31353*10^9, {GrayLevel[0.], AbsoluteThickness[0.25]}}, {3.47129*10^9, {GrayLevel[0.], AbsoluteThickness[0.25]}}, {3.62906*10^9, {GrayLevel[0.], AbsoluteThickness[0.25]}}, {3.78683*10^9, {GrayLevel[0.], AbsoluteThickness[0.25]}}}, {}}

Adding more grid lines can be then be done with:

newgridlines = Replace[
    gridlines,
    {a_, b_} :> {Join[a, {{AbsoluteTime@"Nov 5 2007", Red}}], b}
];

Show[
    plot,
    GridLines -> newgridlines
]

enter image description here

$\endgroup$

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.