I'm trying to plot historical and predicted data into a single line in a single plot. The data ranges from '2020-01-01' '2021-12-31'. When the plot is produced, it plots the data from one month shifted to right in the x-axis. My code is given as follows.
import pandas as pd
index = pd.date_range(start='2020-01-01', end='2021-12-31', freq='M')
series = pd.DataFrame({'num':np.random.randint(0, 50, size=(len(index)))}, index=index)
def plot_series(series):
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
plt.style.use('ggplot')
fig = plt.figure(figsize=(18, 6))
ax = plt.axes()
plt.plot(series.index, series.num.values, color='black', label='Historical')
plt.plot(series.index[18:], series.num.values[18:], color='red', label='Forecasted')
ax.yaxis.set_ticks(np.arange(0, 105, 5))
ax.xaxis.set_major_locator(mdates.MonthLocator(interval=1))
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
plt.legend(loc='best')
plt.title("Time Series Plot: Historial to Forecasted")
plt.xlabel("Month")
plt.ylabel("Score");
plt.gcf().autofmt_xdate(rotation=80)
plt.show();
return fig
Why this behavior is happening and how can fix it?
CodePudding user response:
If you inspect/print the index
object that you generate, you'll see that the dates are at month's end. The
CodePudding user response:
- See the inline comments
ax.set_xticks(ax.get_xticks()[1:-1])
: set the x-ticks to remove the undesired ticks at the beginning and end of the axis.ax.margins(0.015, tight=True)
: or set the margins to be small and tight
- The code was adjusted to only use the object oriented approach,
axes
. - Don't include imports inside the function, they should all be at the top of the script.
- Tested in
python 3.8.11
,matplotlib 3.4.3
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import numpy as np
import pandas as pd
index = pd.date_range(start='2020-01-01', end='2021-12-31', freq='M')
np.random.seed(365) # makes the sample data the same each time
series = pd.DataFrame({'num':np.random.randint(0, 50, size=(len(index)))}, index=index)
def plot_series(series):
fig, ax = plt.subplots(figsize=(18, 6))
ax.plot(series.index, series.num.values, color='black', label='Historical')
ax.plot(series.index[18:], series.num.values[18:], color='red', label='Forecasted')
ax.yaxis.set_ticks(np.arange(0, 105, 5))
ax.xaxis.set_major_locator(mdates.MonthLocator(interval=1))
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
# ax.set_xticks(ax.get_xticks()[1:-1]) # set the x-ticks to remove the first and list value
ax.legend(loc='best')
ax.set(title='Time Series Plot: Historial to Forecasted', xlabel='Month', ylabel='Score')
ax.margins(0.015, tight=True) # or set the margins to be small and tight
fig.autofmt_xdate(rotation=80)
fig.tight_layout()
plot_series(series)
CodePudding user response:
One way I found to fix the x-axis is to use the shift()
function. I shifted the index to one step left: series.index.shift(-1)
Here is the final function:
def plot_series(series):
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
plt.style.use('ggplot')
fig = plt.figure(figsize=(18, 6))
ax = plt.axes()
plt.plot(series.index.shift(-1), series.num.values, color='black', label='Historical')
plt.plot(series.index.shift(-1)[18:], series.num.values[18:], color='red', label='Forecasted')
ax.yaxis.set_ticks(np.arange(0, 105, 5))
ax.xaxis.set_major_locator(mdates.MonthLocator(interval=1))
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
plt.legend(loc='best')
plt.title("Time Series Plot: Historial to Forecasted")
plt.xlabel("Month")
plt.ylabel("Score");
plt.gcf().autofmt_xdate(rotation=80)
plt.show();
return fig