Home > Net >  Matplotlib time series historical vs prediction plot shifting one month in the x-axis
Matplotlib time series historical vs prediction plot shifting one month in the x-axis

Time:09-30

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

Here is the resulting plot. enter image description here

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 month_start_image

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)

enter image description here

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
  • Related