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 noDataValue: The value to be used as the no data value (default is 0)
        :param alpha: The transparency to apply to each raster cell
        :param drawOrder: The draw order determines the order images are stacked if multiple are showing.
        :param cellSize: Specify this parameter to resample the rasters to a different size the cells (e.g.: 30 to
                         resample to cells with dimensions 30 x 30 in units of the raster spatial reference system).
                         NOTE: the processing time increases exponentially with shrinking cellSize values.

        :rtype : (string, list)

def getAsKmlPngAnimation(self, tableName, timeStampedRasters=[], rasterIdFieldName='id', rasterFieldName='raster',
                             documentName='default', noDataValue=0, alpha=1.0, drawOrder=0, cellSize=None,
                             resampleMethod='NearestNeighbour', 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 noDataValue: The value to be used as the no data value (default is 0)
        :param alpha: The transparency to apply to each raster cell
        :param drawOrder: The draw order determines the order images are stacked if multiple are showing.
        :param cellSize: Specify this parameter to resample the rasters to a different size the cells (e.g.: 30 to
                         resample to cells with dimensions 30 x 30 in units of the raster spatial reference system).
                         NOTE: the processing time increases exponentially with shrinking cellSize values.

        :rtype : (string, list)

        """


        if not self.isNumber(noDataValue):
            raise ValueError('RASTER CONVERSION ERROR: noDataValue must be a number.')

        if not self.isNumber(drawOrder):
            raise ValueError('RASTER CONVERSION ERROR: drawOrder must be a number.')

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


        # Extract raster Ids and validate
        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']))

        # Get the color ramp and parameters
        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)

        # Join strings in list to create ramp
        rampString = mappedColorRamp.getPostGisColorRampString()


        # Get a PNG representation of each raster
        result = self.getRastersAsPngs(session=self._session,
                                       tableName=tableName,
                                       rasterIds=rasterIds,
                                       postGisRampString=rampString,
                                       rasterField=rasterFieldName,
                                       rasterIdField=rasterIdFieldName,
                                       cellSize=cellSize,
                                       resampleMethod=resampleMethod)

        binaryPNGs = []

        for row in result:
            binaryPNGs.append(row.png)

        # Determine extents for the KML wrapper file via query
        statement = '''
                    SELECT (foo.metadata).*
                    FROM (
                    SELECT ST_MetaData(ST_Transform({0}, 4326, 'Bilinear')) as metadata
                    FROM {1}
                    WHERE {2}={3}
                    ) As foo;
                    '''.format(rasterFieldName, tableName, rasterIdFieldName, rasterIds[0])

        result = self._session.execute(statement)

        for row in result:
            upperLeftY = row.upperlefty
            scaleY = row.scaley
            height = row.height

            upperLeftX = row.upperleftx
            scaleX = row.scalex
            width = row.width

        north = upperLeftY
        south = upperLeftY + (scaleY * height)
        east = upperLeftX + (scaleX * width)
        west = upperLeftX

        # 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'

        for index, timeStampedRaster in enumerate(timeStampedRasters):
            # Extract variable
            if deltaTime:
                dateTime = timeStampedRaster['dateTime']
                prevDateTime = dateTime - deltaTime


            # GroundOverlay
            groundOverlay = ET.SubElement(document, 'GroundOverlay')
            overlayName = ET.SubElement(groundOverlay, 'name')
            overlayName.text = 'Overlay'

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

                # Create begin tag
                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')

            # DrawOrder
            drawOrderElement = ET.SubElement(groundOverlay, 'drawOrder')
            drawOrderElement.text = str(drawOrder)

            # Define Region
            regionElement = ET.SubElement(groundOverlay, 'Region')
            latLonBox = ET.SubElement(regionElement, 'LatLonBox')

            northElement = ET.SubElement(latLonBox, 'north')
            northElement.text = str(north)

            southElement = ET.SubElement(latLonBox, 'south')
            southElement.text = str(south)

            eastElement = ET.SubElement(latLonBox, 'east')
            eastElement.text = str(east)

            westElement = ET.SubElement(latLonBox, 'west')
            westElement.text = str(west)

            # Href to PNG
            iconElement = ET.SubElement(groundOverlay, 'Icon')
            hrefElement = ET.SubElement(iconElement, 'href')
            hrefElement.text = 'raster{0}.png'.format(index)

            # LatLonBox
            latLonBox = ET.SubElement(groundOverlay, 'LatLonBox')

            northElement = ET.SubElement(latLonBox, 'north')
            northElement.text = str(north)

            southElement = ET.SubElement(latLonBox, 'south')
            southElement.text = str(south)

            eastElement = ET.SubElement(latLonBox, 'east')
            eastElement.text = str(east)

            westElement = ET.SubElement(latLonBox, 'west')
            westElement.text = str(west)

        return ET.tostring(kml), binaryPNGs