How to solve callback error cannot do slice indexing on DatetimeIndex with these indexers

Hello, I’m making a stock market prediction application using plotly dash, but I’m having problems with the dash callback when I want to display an output in the form of a figure. I get an error like the picture below

The output of the prediction model that has been done is as shown below:

Can someone help me solve this problem? Thankyou…

This is my code for running the model:

import pandas as pd
import numpy as np
import random
import time
import math
import os
import datetime as dt
from datetime import timedelta
from keras.models import Sequential
from keras.layers import Dense, LSTM, Conv1D, MaxPooling1D, Flatten, GRU
from keras.callbacks import EarlyStopping, ModelCheckpoint
import warnings
warnings.filterwarnings('ignore')
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
from math import sqrt

def partition_dataset(forecast, data):
    x, y = [], []
    data_len = data.shape[0]
    for i in range(forecast, data_len):
        x.append(data[i-forecast:i,:])
        y.append(data[i, 0])
    
    x = np.array(x)
    y = np.array(y)
    return x, y

def predict_LSTM(df, trainData, testData, forecast):
    
    scaler = MinMaxScaler(feature_range=(0, 1))
    train_dataset = scaler.fit_transform(trainData.values.reshape(-1,1))
    test_dataset = scaler.fit_transform(testData.values.reshape(-1,1))

    trainX, trainY = partition_dataset(forecast, train_dataset[0:,:])
    trainX = np.reshape(trainX, (trainX.shape[0], trainX.shape[1], 1))
    
    testX, testY = partition_dataset(forecast, test_dataset[0:,:])
    testX = np.reshape(testX, (testX.shape[0], testX.shape[1], 1))

    model = Sequential()
    model.add(LSTM(trainX.shape[1] * trainX.shape[2], input_shape=(trainX.shape[1], trainX.shape[2]), return_sequences=True)) 
    model.add(LSTM(trainX.shape[1] * trainX.shape[2], input_shape=(trainX.shape[1], trainX.shape[2]), return_sequences=False)) 
    model.add(Dense(25))
    model.add(Dense(1))
    model.compile(loss='mean_squared_error', optimizer='adam', metrics=["mae"])
    
    es = EarlyStopping(monitor='val_loss', min_delta=1e-10, patience=10, verbose=1)
    mcp = ModelCheckpoint(filepath='LSTM-Stock-Market.h5', monitor='val_loss', verbose=1, save_best_only=True, save_weights_only=True)
    model.fit(trainX, trainY, callbacks=[es, mcp], validation_split=0.2, batch_size=16, epochs=25, verbose=2)
    print(model)

    trainPredict = model.predict(trainX)
    trainPredict = scaler.inverse_transform(trainPredict)
    trainUnscaled = scaler.inverse_transform(trainY.reshape(-1, 1))

    testPredict = model.predict(testX)
    testPredict = scaler.inverse_transform(testPredict)
    testUnscaled = scaler.inverse_transform(testY.reshape(-1, 1))
    
    x_future = forecast
    predictions = np.array([])
    last = testX[-1]
    print(last)
    for i in range(x_future):
        forecast = model.predict(np.array([last]))
        last = np.concatenate([last[1:], forecast])
        predictions = np.concatenate([predictions, forecast[0]])
        predictions = scaler.inverse_transform([predictions])[0]
    print(predictions)
    
    dicts = []
    forecast_date = df.index[-1]
    for i in range(x_future):
        forecast_date = forecast_date + timedelta(days=1)
        dicts.append({'Predictions':predictions[i], "Date": forecast_date})

    future_lstm = pd.DataFrame(dicts).set_index("Date")
    print(future_lstm)

    return trainPredict, testPredict, future_lstm

This is my code for dash app:

import dash
from dash import html, dcc, dash_table
from dash.exceptions import PreventUpdate
import pandas as pd
import numpy as np
import plotly.graph_objs as go
import plotly.express as px
from dash.dependencies import Input, Output
from sklearn.preprocessing import MinMaxScaler
import model
import warnings
warnings.filterwarnings('ignore')

external_scripts = ['/assets/style.css', '/assets/style.css']
app = dash.Dash(__name__, external_scripts=external_scripts)
server = app.server

df = pd.read_csv("Dataset-Stock-Market/Dataset-Stock-Market-Bank-Company.csv")

app.layout = html.Div([
    dcc.Tabs(id="tabs", style = tabs_styles,
    children=[
            dcc.Tab(label='Machine Learning', 
            style = tab_style, selected_style = tab_selected_style,
            children=[
                html.Div(
                    children=[
                        html.H3("Stock Market Prediction Using Deep Learning", style={'textAlign': 'center', 'marginTop': 20}),
                        html.Div([
                            html.P('Select Forecast Time', className = 'fix_label', style = {'color': 'black', 'margin-top': '30px'}),
                            dcc.Slider(id = 'slider-forecast-time',
                                    included = True,
                                    updatemode='drag',
                                    tooltip={'always_visible': True},
                                    min = 20,
                                    max = 101,
                                    step = 1,
                                    value = 40,
                                    marks = {str(yr): str(yr) for yr in range(20, 101, 20)},
                                    className = 'dcc_compon'),
                            html.P('Select Target', className = 'fix_label', style = {'color': 'black', 'margin-top': '30px'}),
                            dcc.RadioItems(id = 'radio-target',
                                        options=[{'label': "High", 'value': "High"}, {'label': "Low", 'value': "Low"},{'label': "Open", 'value': "Open"}, {'label': "Close", 'value': "Close"}],
                                        style = {'color': 'black'}, className = 'dcc_compon'),
                            html.P('Select Dataset', className = 'fix_label', style = {'color': 'black', 'margin-top': '30px'}),
                            dcc.Dropdown(id = 'select-dataset',
                                        multi = False,
                                        clearable = True,
                                        disabled = False,
                                        style = {'display': True},
                                        options=[{'label': 'BCA', 'value': 'BCA'},{'label': 'BRI', 'value': 'BRI'},{'label': 'BNI', 'value': 'BNI'},{'label': 'MANDIRI', 'value': 'MANDIRI'}],
                                        placeholder = 'Select Dataset'),
                            ], 
                            className = "create_container four columns"
                        ),
                        html.Div([
                            dcc.Graph(id='traintest'),
                            ],
                            className = "create_container seven columns"
                        ),
                        html.Div([
                            dcc.Graph(id='result-forecast'),
                            ],
                            style={'marginTop': 600},
                            className = "create_container1"
                        ),
                    ]
                )
        ])
    ])
])

@app.callback(Output('result-forecast', 'figure'),
              [Input('select-dataset', 'value'), 
               Input('radio-target', 'value'), 
               Input('slider-forecast-time', 'value')])
def update_graph(stock, radioval, forecast):
    dropdown = {"BCA": "BCA","BRI": "BRI","BNI": "BNI","MANDIRI": "MANDIRI"}
    radio = {"High": "High Prices", "Low": "Low Prices", "Open": "Open Prices", "Close": "Close Prices" }
    
    trace1 = []
    trace2 = []
    trace3 = []
    trace4 = []
    
    if stock is None:
        raise PreventUpdate
    else:
        stock_market_df = df[df['Stock'] == stock]
        stock_market_df['Date'] = pd.to_datetime(stock_market_df['Date'])
        stock_market_df = stock_market_df.set_index(stock_market_df['Date'])
        stock_market_df.drop(columns=['Date', 'Adj Close', 'Volume'], inplace=True)

        train_data = stock_market_df[radioval][-4000:][0:int(4000 * 0.8)]
        test_data = stock_market_df[radioval][-4000:][int(4000 * 0.8) - int(forecast):]
        
        prediction = model.predict_LSTM(stock_market_df, train_data, test_data, forecast)
        
        train = stock_market_df[:train_data + 1]
        test = stock_market_df[train_data:]
        test['Predictions'] = model.predict_LSTM.testPredict
        
        trace1 = go.Scatter(
            x = train.index,
            y = train[radioval],
            mode = 'lines',
            name = 'Data'
        )
        trace2 = go.Scatter(
            x = test.index,
            y = test['Predictions'],
            mode = 'lines',
            name = 'Prediction'
        )
        trace3 = go.Scatter(
            x = test.index,
            y = test[radioval],
            mode='lines',
            name = 'Ground Truth'
        )
        trace4 = go.Scatter(
            x = model.predict_LSTM.future_lstm.index,
            y = model.predict_LSTM.future_lstm['Predictions'],
            mode='lines',
            name = 'Future Price'
        )
        layout = go.Layout(
            title=f"Future Prediction Stock Market of {', '.join(str(dropdown[i]) for i in selected_dropdown_value)}",
            xaxis = {'title' : "Date"},
            yaxis = {'title' : "Price (USD)"}
        )
        figure = go.Figure(data=[trace1, trace2, trace3, trace4], layout=layout)
        return figure

if __name__ == '__main__':
    app.run_server(debug=True)

Hi,

The error is related to the lines below:

stock_market_df is indexed by datetime, but you are slicing it using integers. You have to transform the integer index in a datetime object. You can use something like pd.Timedelta(days=n) to offset dates.

Hope this helps!

can you give an example of your answer from my code?

My bad, looked at it too fast… It is technically ok to slice with integers (see comment)**…

The problem is actually here:

train_data is a series, so you can’t slice using it.

If you can make a reproducible example, I would be happy to help (you can use px.data.stock() as mock data.

**As a side note, it is a bit dangerous to slice dates as you are doing, since stock_market_df[-4000:] will sort in a decreasing order the dataframe, so your test data in in the past compared to the training one. There are better approaches, like TimeSeriesSplit from sklearn (especially in more sophisticated splits than this one).