Return a sequence of rasters with timestamps as a kml with time markers for animation.

        :param tableName: Name of the table to extract rasters from
        :param timeStampedRasters: List of dictionaries with keys: rasterId, dateTime
               rasterId = a unique integer identifier used to locate the raster (usually value of primary key column)
               dateTime = a datetime object representing the time the raster occurs

               e.g:
               timeStampedRasters = [{ 'rasterId': 1, 'dateTime': datetime(1970, 1, 1)},
                                     { 'rasterId': 2, 'dateTime': datetime(1970, 1, 2)},
                                     { 'rasterId': 3, 'dateTime': datetime(1970, 1, 3)}]

        :param rasterIdFieldName: Name of the id field for rasters (usually the primary key field)
        :param rasterFieldName: Name of the field where rasters are stored (of type raster)
        :param documentName: The name to give to the KML document (will be listed in legend under this name)
        :param alpha: The transparency to apply to each raster cell
        :param noDataValue: The value to be used as the no data value (default is 0)

        :rtype : string

def getAsKmlGridAnimation(self, tableName, timeStampedRasters=[], rasterIdFieldName='id', rasterFieldName='raster',
                              documentName='default', alpha=1.0,  noDataValue=0, discreet=False):
        """
        Return a sequence of rasters with timestamps as a kml with time markers for animation.

        :param tableName: Name of the table to extract rasters from
        :param timeStampedRasters: List of dictionaries with keys: rasterId, dateTime
               rasterId = a unique integer identifier used to locate the raster (usually value of primary key column)
               dateTime = a datetime object representing the time the raster occurs

               e.g:
               timeStampedRasters = [{ 'rasterId': 1, 'dateTime': datetime(1970, 1, 1)},
                                     { 'rasterId': 2, 'dateTime': datetime(1970, 1, 2)},
                                     { 'rasterId': 3, 'dateTime': datetime(1970, 1, 3)}]

        :param rasterIdFieldName: Name of the id field for rasters (usually the primary key field)
        :param rasterFieldName: Name of the field where rasters are stored (of type raster)
        :param documentName: The name to give to the KML document (will be listed in legend under this name)
        :param alpha: The transparency to apply to each raster cell
        :param noDataValue: The value to be used as the no data value (default is 0)

        :rtype : string
        """

        # Validate alpha
        if not (alpha >= 0 and alpha <= 1.0):
            raise ValueError("RASTER CONVERSION ERROR: alpha must be between 0.0 and 1.0.")

        rasterIds = []

        for timeStampedRaster in timeStampedRasters:
            # Validate dictionary
            if 'rasterId' not in timeStampedRaster:
                raise ValueError('RASTER CONVERSION ERROR: rasterId must be provided for each raster.')
            elif 'dateTime' not in timeStampedRaster:
                raise ValueError('RASTER CONVERSION ERROR: dateTime must be provided for each raster.')

            rasterIds.append(str(timeStampedRaster['rasterId']))

        # One color ramp to rule them all
        # Get a single color ramp that is based on the range of values in all the rasters
        minValue, maxValue = self.getMinMaxOfRasters(session=self._session,
                                                     table=tableName,
                                                     rasterIds=rasterIds,
                                                     rasterIdField=rasterIdFieldName,
                                                     rasterField=rasterFieldName,
                                                     noDataValue=noDataValue)

        mappedColorRamp = ColorRampGenerator.mapColorRampToValues(colorRamp=self._colorRamp,
                                                                  minValue=minValue,
                                                                  maxValue=maxValue,
                                                                  alpha=alpha)



        # Default to time delta to None
        deltaTime = None

        # Calculate delta time between images if more than one
        time1 = timeStampedRasters[0]['dateTime']

        if len(timeStampedRasters) >= 2:
            time2 = timeStampedRasters[1]['dateTime']
            deltaTime = time2 - time1

        # Initialize KML Document
        kml = ET.Element('kml', xmlns='http://www.opengis.net/kml/2.2')
        document = ET.SubElement(kml, 'Document')
        docName = ET.SubElement(document, 'name')
        docName.text = documentName

        if not discreet:
            # Embed the color ramp in SLD format
            document.append(ET.fromstring(mappedColorRamp.getColorMapAsContinuousSLD()))
        else:
            values = []
            document.append(ET.fromstring(mappedColorRamp.getColorMapAsDiscreetSLD(values)))

        # Apply special style to hide legend items
        style = ET.SubElement(document, 'Style', id='check-hide-children')
        listStyle = ET.SubElement(style, 'ListStyle')
        listItemType = ET.SubElement(listStyle, 'listItemType')
        listItemType.text = 'checkHideChildren'
        styleUrl = ET.SubElement(document, 'styleUrl')
        styleUrl.text = '#check-hide-children'

        # Collect unique values
        uniqueValues = []

        # Retrieve the rasters and styles
        for timeStampedRaster in timeStampedRasters:
            # Extract variables
            rasterId = timeStampedRaster['rasterId']

            if deltaTime:
                dateTime = timeStampedRaster['dateTime']
                prevDateTime = dateTime - deltaTime

            # Get polygons for each cell in kml format
            statement = '''
                        SELECT x, y, val, ST_AsKML(geom) AS polygon
                        FROM (
                        SELECT (ST_PixelAsPolygons({0})).*
                        FROM {1} WHERE {2}={3}
                        ) AS foo
                        ORDER BY val;
                        '''.format(rasterFieldName, tableName, rasterIdFieldName, rasterId)

            result = self._session.execute(statement)

            # Set initial group value
            groupValue = -9999999.0

            # Add polygons to the kml file with styling
            for row in result:
                # Value will be None if it is a no data value
                if row.val:
                    value = float(row.val)
                else:
                    value = None

                polygonString = row.polygon
                i = int(row.x)
                j = int(row.y)

                # Only create placemarks for values that are not no data values
                if value:
                    if value not in uniqueValues:
                        uniqueValues.append(value)

                    # Create a new placemark for each group of values
                    if value != groupValue:
                        placemark = ET.SubElement(document, 'Placemark')
                        placemarkName = ET.SubElement(placemark, 'name')
                        placemarkName.text = str(value)

                        # Create style tag and setup styles
                        style = ET.SubElement(placemark, 'Style')

                        # Set polygon line style
                        lineStyle = ET.SubElement(style, 'LineStyle')

                        # Set polygon line color and width
                        lineColor = ET.SubElement(lineStyle, 'color')
                        lineColor.text = self.LINE_COLOR
                        lineWidth = ET.SubElement(lineStyle, 'width')
                        lineWidth.text = str(self.LINE_WIDTH)

                        # Set polygon fill color
                        polyStyle = ET.SubElement(style, 'PolyStyle')
                        polyColor = ET.SubElement(polyStyle, 'color')

                        # Convert alpha from 0.0-1.0 decimal to 00-FF string
                        integerAlpha = mappedColorRamp.getAlphaAsInteger()

                        # Get RGB color from color ramp and convert to KML hex ABGR string with alpha
                        integerRGB = mappedColorRamp.getColorForValue(value)
                        hexABGR = '%02X%02X%02X%02X' % (integerAlpha,
                                                        integerRGB[mappedColorRamp.B],
                                                        integerRGB[mappedColorRamp.G],
                                                        integerRGB[mappedColorRamp.R])

                        # Set the polygon fill alpha and color
                        polyColor.text = hexABGR

                        if deltaTime:
                            # Create TimeSpan tag
                            timeSpan = ET.SubElement(placemark, 'TimeSpan')

                            # Create begin and end tags
                            begin = ET.SubElement(timeSpan, 'begin')
                            begin.text = prevDateTime.strftime('%Y-%m-%dT%H:%M:%S')
                            end = ET.SubElement(timeSpan, 'end')
                            end.text = dateTime.strftime('%Y-%m-%dT%H:%M:%S')

                        # Create multigeometry tag
                        multigeometry = ET.SubElement(placemark, 'MultiGeometry')

                        # Create the data tag
                        extendedData = ET.SubElement(placemark, 'ExtendedData')

                        # Add value to data
                        valueData = ET.SubElement(extendedData, 'Data', name='value')
                        valueValue = ET.SubElement(valueData, 'value')
                        valueValue.text = str(value)

                        iData = ET.SubElement(extendedData, 'Data', name='i')
                        valueI = ET.SubElement(iData, 'value')
                        valueI.text = str(i)

                        jData = ET.SubElement(extendedData, 'Data', name='j')
                        valueJ = ET.SubElement(jData, 'value')
                        valueJ.text = str(j)

                        if deltaTime:
                            tData = ET.SubElement(extendedData, 'Data', name='t')
                            valueT = ET.SubElement(tData, 'value')
                            valueT.text = dateTime.strftime('%Y-%m-%dT%H:%M:%S')

                        groupValue = value

                    # Get polygon object from kml string and append to the current multigeometry group
                    polygon = ET.fromstring(polygonString)
                    multigeometry.append(polygon)

        if not discreet:
            # Embed the color ramp in SLD format
            document.append(ET.fromstring(mappedColorRamp.getColorMapAsContinuousSLD()))
        else:
            # Sort the unique values
            uniqueValues.sort()
            document.append(ET.fromstring(mappedColorRamp.getColorMapAsDiscreetSLD(uniqueValues)))

        return ET.tostring(kml)