3
$\begingroup$

It is not very surprising that plotting a PackedArray is faster to plot than a list of pairs (date, value), nonetheless the plotting time may be prohibitive with DateListPlot.

The function benchmark below takes a size as an argument, and compute a list of points to plot in three different ways:

  • ListLinePlot of List of pairs (real, real)
  • DateListPlot of List of pairs (date, real)
  • DateListPlot of TimeSeries

As you can see, ListLinePlot is much faster.

enter image description here

benchmark[n_] := Block[{y, t, t2, ts},
  y = RandomReal[{0, 10}, n];
  t = Sort@RandomReal[{UnixTime[], UnixTime[] + 10000}, n];
  t2 = FromUnixTime /@ t;
  ts = TimeSeries[Transpose@{t2, y}];
  
  {AbsoluteTiming@ListLinePlot[Transpose[{t, y}]], 
    AbsoluteTiming@DateListPlot[Transpose[{t2, y}]], 
    AbsoluteTiming@DateListPlot@ts}[[All, 1]]
]

nvals = 75*Range[60]^2;
tab = ParallelTable[benchmark[n], {n, nvals}];
ListLinePlot[Transpose[{nvals, #}] & /@ Transpose@tab, 
 PlotLabel -> "Timing vs Size", PlotLabels -> {"ListLinePlot", "DateListPlot", 
   "DateListPlot@TimeSeries"}, ImageSize -> Large]

In practice, waiting several seconds can be limiting, for example when plotting multiple curves with long time series with a dynamic range selection.

In such cases, using DateListPlot is prohibitive, so I would like to use ListLinePlot instead. However, the date formatting is neat.

Question Is it possible to display dates on the $x$-axis with ListLinePlot, to mimick the rendering of DateListPlot while preserving an efficient timing?

$\endgroup$
2
  • 1
    $\begingroup$ It is not clear to me what question you are asking. I don't see any serious performance issues in your plot. All three timing results seem to be O[n]. Is there a real, practical problem with plotting 250000 dates taking 10 sec. rather than 2. $\endgroup$
    – m_goldberg
    Commented Feb 28, 2021 at 0:36
  • $\begingroup$ @m_goldberg I edited to ask a specific question. Yes, there a real practical problems where the timing difference has implications and that's how I discovered the timing different between the two (plotting 8 times series with 40000 points each). $\endgroup$
    – anderstood
    Commented Feb 28, 2021 at 7:53

1 Answer 1

2
$\begingroup$

We can use the function System`DateListPlotDump`DateTicks to generate date ticks. Its argument pattern is:

System`DateListPlotDump`DateTicks[{mindate, maxdate}, ndivisons] (* or *)

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

Example:

data1 = TimeSeries[{1, 1, 2, 3, 5, 8, 11}, {"Jan 1, 2015"}];
data2 = TimeSeries[{5, 8, 9, 6, 2, 4, 7}, {"Jan 1, 2015"}];

DateListPlot[{data1, data2}, PlotLegends -> {"first", "second"}]

enter image description here

ListPlot[{data1, data2}, PlotLegends -> {"first", "second"}, Joined -> True, 
 Ticks -> {System`DateListPlotDump`DateTicks[{##}, 5] &, Automatic}]

enter image description here

If you use Frame -> True or use a PlotTheme such as "Detailed" that adds a frame, then we need to use FrameTicks instead of Ticks:

ListPlot[{data1, data2}, PlotLegends -> {"first", "second"}, 
 Joined -> True, 
 FrameTicks -> {{Automatic, Automatic}, 
  {System`DateListPlotDump`DateTicks[{##}, 5] &, Automatic}},
 PlotTheme -> "Detailed"]

enter image description here

To align grid lines with date ticks, we can specify horizontal grids using System`DateListPlotDump`DateTicks:

ListPlot[{data1, data2}, PlotLegends -> {"first", "second"}, 
 Joined -> True,
 GridLines -> {System`DateListPlotDump`DateTicks[{##}, 5] &, Automatic}, 
 GridLinesStyle -> Directive[GrayLevel[0.4, 0.5], AbsoluteThickness[1], 
    AbsoluteDashing[{1, 2}]], 
 FrameTicks -> {{Automatic, Automatic}, 
   {System`DateListPlotDump`DateTicks[{##}, 5] &, Automatic}},
 PlotTheme -> "Scientific"]

enter image description here

FWIW, using Graphics + GraphicsComplex may be faster than ListPlot:

Graphics[GraphicsComplex[Join[data1["Path"], data2["Path"]], 
  {ColorData[97] @ 1, Line[Range @ data1["PathLength"]], 
   ColorData[97] @ 2, Line[data1["PathLength"] + Range @ data2["PathLength"]]}], 
 Axes -> True, 
 AxesOrigin -> {Min[#["FirstTime"] & /@ {data1, data2}], 0}, 
 AspectRatio -> 1/GoldenRatio,
 Ticks -> {System`DateListPlotDump`DateTicks[{##}, 5] &, Automatic}]

enter image description here

$\endgroup$
4
  • $\begingroup$ Nice! Do you know why some PlotThemes (such as Detailed or Scientific) overwrites the ticks so your first solution no longer works? I see no conflicting options in Charting``ResolvePlotTheme["Detailed", ListPlot], yet. $\endgroup$
    – anderstood
    Commented Feb 28, 2021 at 8:59
  • 1
    $\begingroup$ @anderstood, the two themes both add frame; so we need to use FrameTicks instead of Ticks. $\endgroup$
    – kglr
    Commented Feb 28, 2021 at 9:04
  • $\begingroup$ Would you know why data1 = Table[{UnixTime[{2021, 03, 04, 15} + {0, 0, 0, i}], RandomReal[]}, {i, 0, 50}]; ListPlot[data1, Ticks -> {SystemDateListPlotDumpDateTicks[{##}, 10] &, Automatic}]` wrongly shows data on 7th March? data1[[-1, 1]] // FromUnixTime returns correctly 6th March. $\endgroup$
    – anderstood
    Commented Mar 4, 2021 at 20:12
  • 1
    $\begingroup$ @anderstood, System`DateListPlotDump`DateTicks interprets the dates as AbsoluteTime. $\endgroup$
    – kglr
    Commented Mar 4, 2021 at 20:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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