def buildMetadataImage(self, layerInfoList, width): """ Creates the metadata caption for figures in the style used by WMSViz. """ self.metadataItems = self._buildMetadataItems(layerInfoList) self.width = width width=self.width;height=1600;dpi=100;transparent=False figsize=(width / float(dpi), height / float(dpi)) fig = Figure(figsize=figsize, dpi=dpi, facecolor='w', frameon=(not transparent)) axes = fig.add_axes([0.04, 0.04, 0.92, 0.92], frameon=True,xticks=[], yticks=[]) renderer = Renderer(fig.dpi) title, titleHeight = self._drawTitleToAxes(axes, renderer) txt, textHeight = self._drawMetadataTextToAxes(axes, renderer, self.metadataItems) # fit the axis round the text pos = axes.get_position() newpos = Bbox( [[pos.x0, pos.y1 - (titleHeight + textHeight) / height], [pos.x1, pos.y1]] ) axes.set_position(newpos ) # position the text below the title newAxisHeight = (newpos.y1 - newpos.y0) * height txt.set_position( (0.02, 0.98 - (titleHeight/newAxisHeight) )) for loc, spine in axes.spines.iteritems(): spine.set_edgecolor(borderColor) # Draw heading box headingBoxHeight = titleHeight - 1 axes.add_patch(Rectangle((0, 1.0 - (headingBoxHeight/newAxisHeight)), 1, (headingBoxHeight/newAxisHeight), facecolor=borderColor, fill = True, linewidth=0)) # reduce the figure height originalHeight = fig.get_figheight() pos = axes.get_position() topBound = 20 / float(dpi) textHeight = (pos.y1 - pos.y0) * originalHeight newHeight = topBound * 2 + textHeight # work out the new proportions for the figure border = topBound / float(newHeight) newpos = Bbox( [[pos.x0, border], [pos.x1, 1 - border]] ) axes.set_position(newpos ) fig.set_figheight(newHeight) return image_util.figureToImage(fig)
def buildMetadataImage(self, layerInfoList, width): """ Creates the metadata caption for figures in styles that display a title only. """ # Find first non-outline layer. nonOutlineLayers = [l for l in layerInfoList if l.id != outline_layer.OUTLINE_LAYER_ID] layerInfo = nonOutlineLayers[0] if len(nonOutlineLayers) > 0 else None # Get the title of the first set of keyword data, i.e., that for the layer rather than one # of its antecedent layers or datasets. titleText = '' if layerInfo and (len(layerInfo.keywordData) > 0): titleText = layerInfo.keywordData[0].get('title', '') height = 500 dpi = 100 transparent = False figsize = (width / float(dpi), height / float(dpi)) fig = Figure(figsize=figsize, dpi=dpi, facecolor='w', frameon=(not transparent)) renderer = Renderer(fig.dpi) text = fig.text(0.5, 0.98, titleText, fontdict=titleFont, horizontalalignment='center', verticalalignment='top') # Trim the height of the text image. extent = text.get_window_extent(renderer) textHeight = (extent.y1 - extent.y0 + 8) fig.set_figheight(textHeight / float(dpi)) return image_util.figureToImage(fig)
def buildDetailsImage(self, layerInfoList, width): """ Creates the metadata details for figures using templates. """ # Find first non-outline layer. nonOutlineLayers = [l for l in layerInfoList if l.id != outline_layer.OUTLINE_LAYER_ID] layerInfo = nonOutlineLayers[0] if len(nonOutlineLayers) > 0 else None # Flatten the keyword dictionaries, giving priority to entries from descendants over # antecedents. keywordData = {} if layerInfo: for kw in reversed(layerInfo.keywordData): keywordData.update(kw) detailsText = caption_manager.getCaption(layerInfo, keywordData) height = 500 dpi = 100 transparent = False figsize = (width / float(dpi), height / float(dpi)) fig = Figure(figsize=figsize, dpi=dpi, facecolor='w', frameon=(not transparent)) renderer = Renderer(fig.dpi) text = fig.text(0.02, 0.98, detailsText, fontdict=metadataFont, horizontalalignment='left', verticalalignment='top') # Trim the height of the text image. extent = text.get_window_extent(renderer) textHeight = (extent.y1 - extent.y0 + 8) fig.set_figheight(textHeight / float(dpi)) return image_util.figureToImage(fig)
def addAxisToImage(figureOptions, commonLayerParams, layerInfoList, imageCache): """Generates the main figure image with axes. @param figureOptions: overall options for the figure @param commonLayerParams: parameters that apply to all layers @param layerInfoList: list of LayerInfo defining layers to include in the figure @param imageCache: cache of images that have been generated for layers (used for animations where dimensions only vary in the layer over which animation occurs) """ width = int(commonLayerParams.get('WIDTH')) height = int(commonLayerParams.get('HEIGHT')) log.debug("addAxisToImage %d x %d" % (width, height)) dpi = 100; figsize=(width / float(dpi), height / float(dpi)) # Figure has transparent background so that it can be the top layer, making the grid visible. facecolor = 'none' if figureOptions.grid else 'w' edgecolor = 'none' if figureOptions.grid else 'w' aspect = 'equal' transparent=False bounds = commonLayerParams['BBOX'].split(',') log.debug("bounds = %s" % (bounds,)) lonLimits = (float(bounds[0]), float(bounds[2])) latLimits = (float(bounds[1]), float(bounds[3])) log.debug("lonLimits = %s, latLimits = %s" % (lonLimits, latLimits,)) # create an empty image with the axes drawn fig = Figure(figsize=figsize, dpi=dpi, facecolor=facecolor, edgecolor=edgecolor, frameon=(not transparent)) # Add axes, allowing space for the axis legends and centering the map laterally within the figure. sideOffset = 95 sideOffsetFraction = float(sideOffset) / float(width) bottomOffset = 50 bottomOffsetFraction = float(bottomOffset) / float(height) bbox = [sideOffsetFraction, bottomOffsetFraction, (1 - 2 * sideOffsetFraction), (1 - 2 * bottomOffsetFraction)] log.debug("bbox %s" % bbox) axes = fig.add_axes(bbox, frameon=True) axes.patch.set_facecolor(facecolor) axes.set_aspect(aspect) log.debug("axes.get_position(original=False) = %s" % (axes.get_position(original=False),)) axes.set_xlabel('Longitude') axes.set_ylabel('Latitude') axes.set_xlim(lonLimits) axes.set_ylim(latLimits) # Use tick values that are more suited to longitude and latitude if an appropriate set can be # found, otherwise use default ticks. xTicks = _getAxisTicksAtMultiplesOfBase(lonLimits, 15, 6, 9) if xTicks: axes.set_xticks(xTicks) yTicks = _getAxisTicksAtMultiplesOfBase(latLimits, 15, 4, 7) if yTicks: axes.set_yticks(yTicks) axes.xaxis.set_major_formatter(FuncFormatter(xMajorFormatter)) axes.yaxis.set_major_formatter(FuncFormatter(yMajorFormatter)) # Add grid. axes.grid(figureOptions.grid, linestyle='--') axesImage = image_util.figureToImage(fig) # Use the points to get the size of the new image. points = axes.get_position().get_points() bottom = int(round(height * points[0][1])) left = int(round(width * points[0][0])) right = int(round(width * points[1][0])) top = int(round(height * points[1][1])) box = (left, bottom, right, top) # Calculate the new width & height. commonLayerParams['WIDTH'] = str(right-left) commonLayerParams['HEIGHT'] = str(top-bottom) log.debug("commonLayerParams['WIDTH'] = %s" % (commonLayerParams['WIDTH'],)) log.debug("commonLayerParams['HEIGHT'] = %s" % (commonLayerParams['HEIGHT'],)) # Apply the new size to the layer parameters. figure_parameters.updateLayerParameters(layerInfoList, {'WIDTH': commonLayerParams['WIDTH'], 'HEIGHT': commonLayerParams['HEIGHT']}) # Request the new GetMap images. mapImage = buildImage(layerInfoList, imageCache) log.debug("axesImage.size = %s, mapImage.size = %s, box = %s" % (axesImage.size, mapImage.size, box,)) if figureOptions.grid: # Build the combined image on a white, opaque background. size = axesImage.size combinedImage = Image.new('RGBA', size, (255, 255, 255, 255)) # Note that the alpha channel in the images is ignored by paste - the image must be explicitly # set as a mask. combinedImage.paste(mapImage, box, mapImage) combinedImage.paste(axesImage, (0, 0, size[0], size[1]), axesImage) else: # No grid so map image can be pasted into axes. combinedImage = axesImage combinedImage.paste(mapImage, box, mapImage) return combinedImage, box