# How to superimpose a curve fit on top of a TimeSeries plot?

This is a remarkably simple question for which I was not able to find an answer in the documentation.

For concreteness, suppose that we have some time series data, such as this (example taken straight from the Mathematica documentation):

ts = TimeSeries[FinancialData["MSFT", "Jan. 1, 2008"]];


...which we can plot with

DateListPlot[ts]


...to get this

Now, I can generate a linear fit to this data (which will be pretty lame, of course) with

fit = FindFit[ts, a + b t, {a, b}, t]


{a -> -526.325, b -> 1.58402*10^-7}

My question is: how do I superimpose the line corresponding to this linear approximation on top of the DateListPlot shown above?

Is there a simple way to do this?

NB: In case it matters, I'm interested in solutions that can be extrapolated beyond the data's original range. For example, I'd like to superimpose the line fit above over the curve shown below, so that the domain of the fit extends over all of the horizontal PlotRange (through the end of 2020):

DateListPlot[ts, PlotRange -> {{Automatic, {2020, 12, 31}}, {0, 150}}]


(* set end date *)
With[{tend = {2020, 12, 31}},
(* timings *)
With[{times = ts["Times"], extension = Rest[DateRange[ts["LastTime"], AbsoluteTime[tend]]]},
(* localize vars *)
Block[{lmf, abst, est, ext, y, t, lts, xlts},
(* linear fit *)
lmf = LinearModelFit[ts, abst, abst];
(* linear est *)
est = lmf["Response"] - lmf["FitResiduals"];
(* linear ts over sample *)
lts = TimeSeries[est, {times}, DateFunction :> (DateList[#] &)];
(* out-of-sample est *)
ext = lmf["Function"] /@ extension;
(* out-of-sample ts *)
xlts = TimeSeries[ext, {extension}, DateFunction :> (DateList[#] &)];
(* prepare output plot *)
DateListPlot[
{ts, lts, xlts},
PlotRange -> {{Automatic, tend}, {0, 150}},
PlotLegends -> Placed[
{TimeSeries, LinearModelFit, Row[{LinearModelFit , , out , , of, , sample}]}, Below]
]
]
]
]


This might work. It is important to put DateListPlot first into Show in order to get appropriate coordinate axes.

ts = TimeSeries[FinancialData["MSFT", "Jan. 1, 2008"]];
fit = FindFit[ts, a + b t, {a, b}, t];
f = t \[Function] Evaluate[ b t + a /. fit];
ts2 = Transpose[{ts["Times"], Map[f, ts["Times"]]}];
Show[
DateListPlot[ts],
ListLinePlot[ts2, PlotStyle -> ColorData[97][2]]
]


You can just use the fit as an epilog if you appropriately extract the times from your data. First define fit as a function:

fit[t_] = a + b t /. FindFit[ts, a + b t, {a, b}, t];


and then make a line as an epilog to your DateListPlot:

Module[{firstlast = ts["Times"][[{1, -1}]]},
DateListPlot[ts, Epilog -> Line[{#, fit@#} & /@ firstlast]
]
]


I was also trying to do something similar, but in Mathematica 12, the above code doesn't work. It gives you this error: "FindFit::ivar: Dataset [<<4>>] is not a valid variable." I'm very new to Mathematica and didn't find that particularly helpful.

To make it work you have to enable the "Legacy" switch when you get the data:

 ts = TimeSeries[FinancialData["MSFT", "Jan. 1, 2008", Method -> "Legacy"]];


Once you do this, the rest of it works as before.

• Legacy drops the currency unit.To avoid that, don't use Legacy and do this instead: FindFit[ts["Path"], a + b t, {a, b}, t] May 27, 2019 at 21:32
• That is very helpful. Thank you. Would you mind explaining why that works? I spent a good deal of this afternoon trying to do what I anticipated would be a very simple thing and found zero help in the documentation. When you get the FinancialData data structure back, there doesn't seem to be a way to look at how it is structured (or the data). I'm coming from an R and MATLAB background where you can peek at the actual data in any given structure and I'm struggling to understand how Mathematica structures are put together or otherwise get meaningful information about them. Thanks! May 27, 2019 at 21:42
• Take a look at the "Details and Options" section of the TimeSeries docs. It describes the properties that can be used to introspect/extract information. If you want to look at the symbolic representation of ts try FullForm@ts. That representation may change in future versions, but you can drill in. To get the internal QuantityArray: First@Cases[ts, _StructuredArray, Infinity]. Hope that helps. May 27, 2019 at 23:48