def tiles(self): """ Generator that yields an algebra-ready data dictionary for each tile in the aggregator's tile range. """ # Check if any tiles have been matched if not self.tilerange: return algebra_parser = RasterAlgebraParser() for tilex in range(self.tilerange[0], self.tilerange[2] + 1): for tiley in range(self.tilerange[1], self.tilerange[3] + 1): # Prepare a data dictionary with named tiles for algebra evaluation data = {} for name, layerid in self.layer_dict.items(): tile = get_raster_tile(layerid, self.zoom, tilex, tiley) if tile: data[name] = tile else: break # Ignore this tile if it is missing in any of the input layers if len(data) < len(self.layer_dict): continue # Compute raster algebra result = algebra_parser.evaluate_raster_algebra( data, self.formula) # Convert band data to masked array result_data = numpy.ma.masked_values( result.bands[0].data(), result.bands[0].nodata_value, ) # Apply rasterized geometry as mask if clip geometry was provided if self.geom: result_data = self.mask_by_geom(result, result_data) yield result_data.compressed()
def tiles(self): """ Generator that yields an algebra-ready data dictionary for each tile in the aggregator's tile range. """ # Check if any tiles have been matched if not self.tilerange: return algebra_parser = RasterAlgebraParser() for tilex in range(self.tilerange[0], self.tilerange[2] + 1): for tiley in range(self.tilerange[1], self.tilerange[3] + 1): # Prepare a data dictionary with named tiles for algebra evaluation data = {} for name, layerid in self.layer_dict.items(): tile = get_raster_tile(layerid, self.zoom, tilex, tiley) if tile: data[name] = tile else: break # Ignore this tile if it is missing in any of the input layers if len(data) < len(self.layer_dict): continue # Compute raster algebra result = algebra_parser.evaluate_raster_algebra(data, self.formula) # Convert band data to masked array result_data = numpy.ma.masked_values( result.bands[0].data(), result.bands[0].nodata_value, ) # Apply rasterized geometry as mask if clip geometry was provided if self.geom: result_data = self.mask_by_geom(result, result_data) yield result_data.compressed()
def get_tile(self, layer_id, zlevel=None): """ Returns a tile for rendering. If the tile does not exists, higher level tiles are searched and warped to lower level if found. """ if self.is_pixel_request: tilez = self.max_zoom # Derive the tile index from the input coordinates. xcoord = float(self.kwargs.get('xcoord')) ycoord = float(self.kwargs.get('ycoord')) bbox = [xcoord, ycoord, xcoord, ycoord] indexrange = tile_index_range(bbox, tilez) tilex = indexrange[0] tiley = indexrange[1] else: # Get tile indices from the request url parameters. tilez = int(self.kwargs.get('z')) tilex = int(self.kwargs.get('x')) tiley = int(self.kwargs.get('y')) return get_raster_tile(layer_id, tilez, tilex, tiley)
def get(self, request): # Initiate algebra parser parser = RasterAlgebraParser() # Get formula from request formula = request.GET.get('formula') # Get id list from request ids = self.get_ids() # Compute tile index range zoom, xmin, ymin, xmax, ymax = self.get_tile_range() # Check maximum size of target raster in pixels max_pixels = getattr(settings, 'RASTER_EXPORT_MAX_PIXELS', EXPORT_MAX_PIXELS) if WEB_MERCATOR_TILESIZE * (xmax - xmin) * WEB_MERCATOR_TILESIZE * (ymax - ymin) > max_pixels: raise RasterAlgebraException('Export raster too large.') # Construct an empty raster with the output dimensions result_raster = self.construct_raster(zoom, xmin, xmax, ymin, ymax) target = result_raster.bands[0] # Get raster data as 1D arrays and store in dict that can be used # for formula evaluation. for xindex, x in enumerate(range(xmin, xmax + 1)): for yindex, y in enumerate(range(ymin, ymax + 1)): data = {} for name, layerid in ids.items(): tile = get_raster_tile(layerid, zoom, x, y) if tile: data[name] = tile # Ignore this tile if data is not found for all layers if len(data) != len(ids): continue # Evaluate raster algebra expression, return 400 if not successful try: # Evaluate raster algebra expression tile_result = parser.evaluate_raster_algebra(data, formula) except: raise RasterAlgebraException('Failed to evaluate raster algebra.') # Update nodata value on target target.nodata_value = tile_result.bands[0].nodata_value # Update results raster with algebra target.data( data=tile_result.bands[0].data(), size=(WEB_MERCATOR_TILESIZE, WEB_MERCATOR_TILESIZE), offset=(xindex * WEB_MERCATOR_TILESIZE, yindex * WEB_MERCATOR_TILESIZE), ) # Create filename base with datetime stamp filename_base = 'algebra_export' # Add name slug to filename if provided if request.GET.get('filename', ''): # Sluggify name slug = slugify(request.GET.get('filename')) # Remove all unwanted characters slug = "".join([c for c in slug if re.match(r'\w|\-', c)]) # Limit length of custom name slug slug = slug[:MAX_EXPORT_NAME_LENGTH] # Add name slug to filename base filename_base += '_' + slug filename_base += '_{0}'.format(datetime.now().strftime('%Y_%m_%d_%H_%M')) # Compress resulting raster file into a zip archive raster_workdir = getattr(settings, 'RASTER_WORKDIR', None) dest = NamedTemporaryFile(dir=raster_workdir, suffix='.zip') dest_zip = zipfile.ZipFile(dest.name, 'w', allowZip64=True) dest_zip.write( filename=self.exportfile.name, arcname=filename_base + '.tif', compress_type=zipfile.ZIP_DEFLATED, ) # Write README.txt and COLORMAP.txt files to zip file self.write_readme(dest_zip) self.write_colormap(dest_zip) # Close zip file before returning dest_zip.close() # Create file based response containing zip file and return for download response = FileResponse( open(dest.name, 'rb'), content_type='application/zip' ) response['Content-Disposition'] = 'attachment; filename="{0}"'.format(filename_base + '.zip') return response
def get_raster_tile(self, layerid, zoom, tilex, tiley): return get_raster_tile(layerid, zoom, tilex, tiley)