def draw(self, dataTable, functionTable, performanceTable, rowIndex, colIndex, cellContents, labelAttributes, plotDefinitions): """Draw the plot legend content, which is more often text than graphics. @type dataTable: DataTable @param dataTable: Contains the data to describe, if any. @type functionTable: FunctionTable @param functionTable: Defines functions that may be used to transform data. @type performanceTable: PerformanceTable @param performanceTable: Measures and records performance (time and memory consumption) of the drawing process. @type rowIndex: int @param rowIndex: Row number of the C{cellContents} to fill. @type colIndex: int @param colIndex: Column number of the C{cellContents} to fill. @type cellContents: dict @param cellContents: Dictionary that maps pairs of integers to SVG graphics to draw. @type labelAttributes: CSS style dict @param labelAttributes: Style properties that are defined at the level of the legend and must percolate down to all drawables within the legend. @type plotDefinitions: PlotDefinitions @type plotDefinitions: The dictionary of key-value pairs that forms the <defs> section of the SVG document. @rtype: 2-tuple @return: The next C{rowIndex} and C{colIndex} in the sequence. """ svg = SvgBinding.elementMaker svgId = self.get("svgId") if svgId is None: output = svg.g() else: output = svg.g(**{"id": svgId}) inlineSvg = self.getchildren() fileName = self.get("fileName") if len(inlineSvg) == 1 and fileName is None: svgBinding = copy.deepcopy(inlineSvg[0]) elif len(inlineSvg) == 0 and fileName is not None: svgBinding = SvgBinding.loadXml(fileName) else: raise defs.PmmlValidationError("PlotLegendSvg should specify an inline SVG or a fileName but not both or neither") sx1, sy1, sx2, sy2 = PlotSvgAnnotation.findSize(svgBinding) nominalHeight = sy2 - sy1 nominalWidth = sx2 - sx1 # TODO: set this correctly from the text height rowHeight = 30.0 # output["transform"] = "translate(%r, %r) scale(%r, %r)" % (-sx1, -sy1, rowHeight/float(sx2 - sx1), rowHeight/float(sy2 - sy1)) output["transform"] = "translate(%r, %r) scale(%r, %r)" % (-sx1 - 0.5*nominalWidth*rowHeight/nominalHeight, -sy1 - 0.75*rowHeight, rowHeight/nominalHeight, rowHeight/nominalHeight) output.append(svgBinding) cellContents[rowIndex, colIndex] = svg.g(output) cellContents[rowIndex, colIndex].text = " " # TODO: set the width correctly, too colIndex += 1 return rowIndex, colIndex
def draw(self, state, plotCoordinates, plotDefinitions, performanceTable): """Draw the plot element. This stage consists of creating an SVG image of the pre-computed data. @type state: ad-hoc Python object @param state: State information that persists long enough to use quantities computed in C{prepare} in the C{draw} stage. This is a work-around of lxml's refusal to let its Python instances maintain C{self} and it is unrelated to DataTableState. @type plotCoordinates: PlotCoordinates @param plotCoordinates: The coordinate system in which this plot element will be placed. @type plotDefinitions: PlotDefinitions @type plotDefinitions: The dictionary of key-value pairs that forms the <defs> section of the SVG document. @type performanceTable: PerformanceTable @param performanceTable: Measures and records performance (time and memory consumption) of the drawing process. @rtype: SvgBinding @return: An SVG fragment representing the fully drawn plot element. """ svg = SvgBinding.elementMaker x1 = float(self["x1"]) y1 = float(self["y1"]) x2 = float(self["x2"]) y2 = float(self["y2"]) inlineSvg = self.getchildren() fileName = self.get("fileName") if len(inlineSvg) == 1 and fileName is None: svgBinding = inlineSvg[0] elif len(inlineSvg) == 0 and fileName is not None: svgBinding = SvgBinding.loadXml(fileName) else: raise defs.PmmlValidationError( "PlotSvgContent should specify an inline SVG or a fileName but not both or neither" ) sx1, sy1, sx2, sy2 = PlotSvgAnnotation.findSize(svgBinding) subCoordinates = PlotCoordinatesWindow(plotCoordinates, sx1, sy1, sx2, sy2, x1, y1, x2 - x1, y2 - y1) tx0, ty0 = subCoordinates(0.0, 0.0) tx1, ty1 = subCoordinates(1.0, 1.0) transform = "translate(%r, %r) scale(%r, %r)" % (tx0, ty0, tx1 - tx0, ty1 - ty0) attribs = {"transform": transform} svgId = self.get("svgId") if svgId is not None: attribs["id"] = svgId if "style" in svgBinding.attrib: attribs["style"] = svgBinding.attrib["style"] return svg.g(*(copy.deepcopy(svgBinding).getchildren()), **attribs)
def draw(self, state, plotCoordinates, plotDefinitions, performanceTable): """Draw the plot element. This stage consists of creating an SVG image of the pre-computed data. @type state: ad-hoc Python object @param state: State information that persists long enough to use quantities computed in C{prepare} in the C{draw} stage. This is a work-around of lxml's refusal to let its Python instances maintain C{self} and it is unrelated to DataTableState. @type plotCoordinates: PlotCoordinates @param plotCoordinates: The coordinate system in which this plot element will be placed. @type plotDefinitions: PlotDefinitions @type plotDefinitions: The dictionary of key-value pairs that forms the <defs> section of the SVG document. @type performanceTable: PerformanceTable @param performanceTable: Measures and records performance (time and memory consumption) of the drawing process. @rtype: SvgBinding @return: An SVG fragment representing the fully drawn plot element. """ svg = SvgBinding.elementMaker x1 = float(self["x1"]) y1 = float(self["y1"]) x2 = float(self["x2"]) y2 = float(self["y2"]) inlineSvg = self.getchildren() fileName = self.get("fileName") if len(inlineSvg) == 1 and fileName is None: svgBinding = inlineSvg[0] elif len(inlineSvg) == 0 and fileName is not None: svgBinding = SvgBinding.loadXml(fileName) else: raise defs.PmmlValidationError("PlotSvgContent should specify an inline SVG or a fileName but not both or neither") sx1, sy1, sx2, sy2 = PlotSvgAnnotation.findSize(svgBinding) subCoordinates = PlotCoordinatesWindow(plotCoordinates, sx1, sy1, sx2, sy2, x1, y1, x2 - x1, y2 - y1) tx0, ty0 = subCoordinates(0.0, 0.0) tx1, ty1 = subCoordinates(1.0, 1.0) transform = "translate(%r, %r) scale(%r, %r)" % (tx0, ty0, tx1 - tx0, ty1 - ty0) attribs = {"transform": transform} svgId = self.get("svgId") if svgId is not None: attribs["id"] = svgId if "style" in svgBinding.attrib: attribs["style"] = svgBinding.attrib["style"] return svg.g(*(copy.deepcopy(svgBinding).getchildren()), **attribs)
def makeMarker(svgIdMarker, marker, style, plotSvgMarker): """Construct a marker from a set of known shapes or an SVG pictogram. @type svgIdMarker: string @param svgIdMarker: SVG id for the new marker. @type marker: string @param marker: Name of the marker shape; must be one of PLOT-MARKER-TYPE. @type style: dict @param style: CSS style for the marker in dictionary form. @type plotSvgMarker: PmmlBinding or None @param plotSvgMarker: A PlotSvgMarker element, which either contains an inline SvgBinding or a fileName pointing to an external image. @rtype: SvgBinding @return: The marker image, appropriate for adding to a PlotDefinitions. """ svg = SvgBinding.elementMaker style["stroke"] = style["marker-outline"] del style["marker-outline"] markerSize = float(style["marker-size"]) del style["marker-size"] if marker == "circle": return svg.circle(id=svgIdMarker, cx="0", cy="0", r=repr(markerSize), style=PlotStyle.toString(style)) elif marker == "square": p = markerSize m = -markerSize return svg.path(id=svgIdMarker, d="M %r,%r L %r,%r L %r,%r L %r,%r z" % (m,m, p,m, p,p, m,p), style=PlotStyle.toString(style)) elif marker == "diamond": p = math.sqrt(2.0) * markerSize m = -math.sqrt(2.0) * markerSize return svg.path(id=svgIdMarker, d="M %r,0 L 0,%r L %r,0 L 0,%r z" % (m, m, p, p), style=PlotStyle.toString(style)) elif marker == "plus": p = markerSize m = -markerSize if style["stroke"] == "none": style["stroke"] = style["fill"] style["fill"] = "none" return svg.path(id=svgIdMarker, d="M %r,0 L %r,0 M 0,%r L 0,%r" % (m, p, m, p), style=PlotStyle.toString(style)) elif marker == "times": p = math.sqrt(2.0) * markerSize m = -math.sqrt(2.0) * markerSize if style["stroke"] == "none": style["stroke"] = style["fill"] style["fill"] = "none" return svg.path(id=svgIdMarker, d="M %r,%r L %r,%r M %r,%r L %r,%r" % (m,m, p,p, p,m, m,p), style=PlotStyle.toString(style)) elif marker == "svg": if plotSvgMarker is None: raise defs.PmmlValidationError("When marker is \"svg\", a PlotSvgMarker must be provided") inlineSvg = plotSvgMarker.getchildren() fileName = plotSvgMarker.get("fileName") if len(inlineSvg) == 1 and fileName is None: svgBinding = inlineSvg[0] elif len(inlineSvg) == 0 and fileName is not None: svgBinding = SvgBinding.loadXml(fileName) else: raise defs.PmmlValidationError("PlotSvgMarker should specify an inline SVG or a fileName but not both or neither") sx1, sy1, sx2, sy2 = PlotSvgAnnotation.findSize(svgBinding) tx1, ty1 = -markerSize, -markerSize tx2, ty2 = markerSize, markerSize transform = "translate(%r, %r) scale(%r, %r)" % (tx1 - sx1, ty1 - sy1, (tx2 - tx1)/float(sx2 - sx1), (ty2 - ty1)/float(sy2 - sy1)) return svg.g(copy.deepcopy(svgBinding), id=svgIdMarker, transform=transform)