Linking animation frames to time series data (hdf5, numpy) in Python reader plugin

Hello,

I have been attempting to create a reader plugin for my hdf5 dataset. The problem I am facing is that animation frames are consistently showing as the default, 10 steps between 1 and 10 inclusive. Is this expected? I have had trouble finding insight in the documentation, but I had expected setting executive.TIME_STEPS() and executive.TIME_RANGE() to link my data to the animation. Is there a way to set these from the reader, or am I going about this the wrong way? I have included an example reader similar to my own using a randomly generated numpy array.

"""
ParaView Python Reader for a 4D NumPy array of shape (T, X, Y, Z).
"""
from __future__ import division, print_function

import os
import numpy as np
import vtk
from paraview.util.vtkAlgorithm import *
from vtkmodules.util import numpy_support as vtknp

def generate_seeded_4d_array(T, X, Y, Z, seed=0):
    """
    Generate a 4D NumPy array of shape (T, X, Y, Z) with random values.
    The 'seed' parameter ensures reproducible random numbers.
    """
    np.random.seed(seed)
    # Creates a 4D array with values in [0, 1)
    data = np.random.rand(T, X, Y, Z)
    return data


@smproxy.reader(name="Random4DNumPyReader",
                label="Random 4D NumPy Reader",
                extensions=["npy"],
                file_description="4D NumPy array (T, X, Y, Z)")
class Random4DNumPyReader(VTKPythonAlgorithmBase):
    def __init__(self):
        # We have one output port (the 3D image) and no inputs.
        VTKPythonAlgorithmBase.__init__(self,
                                        nInputPorts=0,
                                        nOutputPorts=1,
                                        outputType="vtkImageData")

        self.__FileName = None
        self.__Data = None
        self.__TimeSteps = None

    #### FileName property ####
    @smproperty.stringvector(name="FileName")
    @smdomain.filelist()
    def SetFileName(self, fname):
        """Called by ParaView when the user selects a file."""
        if self.__FileName != fname:
            self.__FileName = fname
            self.Modified()  # Mark the reader "modified" so it reloads

    def RequestInformation(self, request, inInfo, outInfo):
        """
        ParaView calls RequestInformation first to query the data extents,
        time steps, etc.
        """
        if not self.__FileName or not os.path.exists(self.__FileName):
            return 1

        executive = self.GetExecutive()

        # Load the 4D array.  Shape expected: (T, X, Y, Z)
        data_array = np.load(self.__FileName)
        self.__Data = data_array  # Keep a reference for RequestData

        # Suppose data_array.shape = (T, X, Y, Z)
        shape = data_array.shape
        if len(shape) != 4:
            raise RuntimeError(
                f"Expected a 4D array (T, X, Y, Z), got shape={shape}"
            )

        T, X, Y, Z = shape

        # Define discrete time steps as integers 0..T-1 (or floats)
        self.__TimeSteps = list(range(T))
        
        # Tell ParaView about the available time steps
        outInfo_0 = outInfo.GetInformationObject(0)


        outInfo_0.Remove(executive.TIME_STEPS())
        outInfo_0.Remove(executive.TIME_RANGE())
        for t in self.__TimeSteps:
            outInfo_0.Append(executive.TIME_STEPS(), t)
        
        outInfo_0.Append(executive.TIME_RANGE(), self.__TimeSteps[0])
        outInfo_0.Append(executive.TIME_RANGE(), self.__TimeSteps[-1])

        extent = [0, X - 1, 0, Y - 1, 0, Z - 1]
        outInfo_0.Set(
            executive.WHOLE_EXTENT(),
            extent,
            6
        )

        return 1

    def RequestData(self, request, inInfo, outInfo):
        if self.__Data is None:
            return 1
        
        executive = self.GetExecutive()

        time = request.Get(executive.UPDATE_TIME_STEP())
        if self.__TimeSteps:
            if time not in self.__TimeSteps:
                idx = int(round(time))
            else:
                idx = int(time)
        else:
            idx = 0

        vol_3d = self.__Data[idx, :, :, :]

        output = vtk.vtkImageData.GetData(outInfo, 0)

        X, Y, Z = vol_3d.shape

        output.SetDimensions(X, Y, Z)

        output.AllocateScalars(vtk.VTK_FLOAT, 1)

        flat_data = vol_3d.astype(np.float32).ravel(order="C")
        vtk_array = vtknp.numpy_to_vtk(flat_data, deep=True, array_type=vtk.VTK_FLOAT)
        vtk_array.SetName("RandomData")
        output.GetPointData().SetScalars(vtk_array)

        output.GetInformation().Set(
            vtk.vtkDataObject.DATA_TIME_STEP(), time
        )
        return 1

I have seen that many many times. The following code will probably help

animationScene1 = GetAnimationScene()
animationScene1.UpdateAnimationUsingDataTimeSteps()