5

I am creating these timeseries plots specifically stl decomposition and already managed to get all the plots into one. The issue I am having is having them shown side by side like the solution here. I tried the solution on the link but it did not work, instead I kept getting an empty plot on the top. I have four time series plots and managed to get them outputted on the bottom of each other however I would like to have them side by side or two side by side and the last two on the bottom side by side.

Then for the dates on the xaxis, I have already tried using ax.xaxis.set_major_formatter(DateFormatter('%b %Y')) but it is not working on the code below since the res.plot function won't allow it.

I have already searched everywhere but I can't find the solution to my issue. I would appreciate any help.

Data

      Date     Crime
0   2018-01-01  149
1   2018-01-02  88
2   2018-01-03  86
3   2018-01-04  100
4   2018-01-05  123
... ... ...
664 2019-10-27  142
665 2019-10-28  113
666 2019-10-29  126
667 2019-10-30  120
668 2019-10-31  147

Code

from statsmodels.tsa.seasonal import STL
import matplotlib.pyplot as plt
import seaborn as sns
from pandas.plotting import register_matplotlib_converters 
from matplotlib.dates import DateFormatter

register_matplotlib_converters()
sns.set(style='whitegrid', palette = sns.color_palette('winter'), rc={'axes.titlesize':17,'axes.labelsize':17, 'grid.linewidth': 0.5})
plt.rc("axes.spines", top=False, bottom = False, right=False, left=False)
plt.rc('font', size=13)
plt.rc('figure',figsize=(17,12))

#fig=plt.figure()
#fig, axes = plt.subplots(2, sharex=True)

#fig,(ax,ax2,ax3,ax4) = plt.subplots(1,4,sharey=True)

#fig, ax = plt.subplots()
#fig, axes = plt.subplots(1,3,sharex=True, sharey=True, figsize=(12,5))
#ax.plot([0, 0], [0,1]) 


stl = STL(seatr, seasonal=13)
res = stl.fit()
res.plot()    
plt.title('Seattle', fontsize = 20, pad=670)

stl2 = STL(latr, seasonal=13)
res2 = stl.fit()
res2.plot()  
plt.title('Los Angles', fontsize = 20, pad=670)

stl3 = STL(sftr, seasonal=13)
res3 = stl.fit()
res3.plot()  
plt.title('San Francisco', fontsize = 20, pad=670)

stl4 = STL(phtr, seasonal=13)
res4 = stl.fit()
res4.plot()  
plt.title('Philadelphia', fontsize = 20, pad=670)

#ax.xaxis.set_major_formatter(DateFormatter('%b %Y'))

One of the Plots One of the Plots

Whole Output
Whole Output

Mr. T
  • 11,960
  • 10
  • 32
  • 54
Aylin
  • 61
  • 4

1 Answers1

3

Here is an example using artificial data. The main idea is to group the outputs in to DataFrames and then to plot these using the pandas plot function.

Note that I had to change your code to use stl2, stl3 and stl4 when fitting.

from statsmodels.tsa.seasonal import STL
import matplotlib.pyplot as plt
import seaborn as sns
from pandas.plotting import register_matplotlib_converters 
from matplotlib.dates import DateFormatter

register_matplotlib_converters()
sns.set(style='whitegrid', palette = sns.color_palette('winter'), rc={'axes.titlesize':17,'axes.labelsize':17, 'grid.linewidth': 0.5})
plt.rc("axes.spines", top=False, bottom = False, right=False, left=False)
plt.rc('font', size=13)
plt.rc('figure',figsize=(17,12))


idx = pd.date_range("1-1-2020", periods=200, freq="M")
seas = 10*np.sin(np.arange(200) * np.pi/12)
trend = np.arange(200) / 10.0
seatr = pd.Series(trend + seas + np.random.standard_normal(200), name="Seattle", index=idx)
latr = pd.Series(trend + seas + np.random.standard_normal(200), name="LA", index=idx)
sftr = pd.Series(trend + seas + np.random.standard_normal(200), name="SF", index=idx)
phtr = pd.Series(trend + seas + np.random.standard_normal(200), name="Philly", index=idx)

stl = STL(seatr, seasonal=13)
res = stl.fit()

stl2 = STL(latr, seasonal=13)
res2 = stl2.fit()

stl3 = STL(sftr, seasonal=13)
res3 = stl3.fit()

stl4 = STL(phtr, seasonal=13)
res4 = stl4.fit()

data = pd.concat([seatr, latr, sftr, phtr], 1)
trends = pd.concat([res.trend, res2.trend, res3.trend, res4.trend], 1)
seasonals = pd.concat([res.seasonal, res2.seasonal, res3.seasonal, res4.seasonal], 1)
resids = pd.concat([res.resid, res2.resid, res3.resid, res4.resid], 1)

fig, axes = plt.subplots(4,1)
data.plot(ax=axes[0])
trends.plot(ax=axes[1])
seasonals.plot(ax=axes[2])
resids.plot(ax=axes[3])

This produces:

Output of multiple STL

Kevin S
  • 2,595
  • 16
  • 22
  • Thank you for your answer, is there a way to just use the plots I already have but just put them side by side rather than in one plot? – Aylin Oct 31 '20 at 21:40
  • If you want them side by side, then you could just plot each column in its own axes, something like `for i, col in trends: trends[col].plot(ax=axes[i])`. I'm not totally clear what you expect the figure to look like. Do you want a 4 by 1? Or a 16 by 1 with groups of 4? – Kevin S Nov 01 '20 at 08:00
  • Thank you, a 4 by 1 where each stl decomposition plot is shown side by side in one row. Like the solution in this link here: https://stackoverflow.com/questions/45184055/how-to-plot-multiple-seasonal-decompose-plots-in-one-figure I tried to follow the solution but was not able to get the same results so I wanted a simpler version of it. – Aylin Nov 02 '20 at 15:47