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 performanceTable.begin("PlotLegendNumber") myLabelAttributes = dict(labelAttributes) style = PlotStyle.toDict(myLabelAttributes["style"]) style.update(self.getStyleState()) myLabelAttributes["style"] = PlotStyle.toString(style) myLabelAttributes["font-size"] = style["font-size"] svgId = self.get("svgId") if svgId is not None: myLabelAttributes["id"] = svgId try: float(self.text) except (ValueError, TypeError): self.text = "0" digits = self.get("digits") if digits is not None: astext = PlotNumberFormat.roundDigits(float(self.text), int(digits)) else: astext = PlotNumberFormat.toUnicode(self.text) cellContents[rowIndex, colIndex] = svg.text(astext, **myLabelAttributes) colIndex += 1 performanceTable.end("PlotLegendNumber") return rowIndex, colIndex
def checkStyleProperties(self): """Verify that all properties currently requested in the C{style} attribute are in the legal C{styleProperties} list. @raise PmmlValidationError: If the list contains an unrecognized style property name, raise an error. Otherwise, silently pass. """ style = self.get("style") if style is not None: for name in PlotStyle.toDict(style).keys(): if name not in self.styleProperties: raise defs.PmmlValidationError("Unrecognized style property: \"%s\"" % name)
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 performanceTable.begin("PlotLegendNumber") myLabelAttributes = dict(labelAttributes) style = PlotStyle.toDict(myLabelAttributes["style"]) style.update(self.getStyleState()) myLabelAttributes["style"] = PlotStyle.toString(style) myLabelAttributes["font-size"] = style["font-size"] svgId = self.get("svgId") if svgId is not None: myLabelAttributes["id"] = svgId try: float(self.text) except (ValueError, TypeError): self.text = "0" digits = self.get("digits") if digits is not None: astext = PlotNumberFormat.roundDigits(float(self.text), int(digits)) else: astext = PlotNumberFormat.toUnicode(self.text) cellContents[rowIndex, colIndex] = svg.text(astext, **myLabelAttributes) colIndex += 1 performanceTable.end("PlotLegendNumber") return rowIndex, colIndex
def getStyleState(self): """Get the current state of the style (including any unmodified defaults) as a dictionary. @rtype: dict @return: Dictionary mapping style property names to their values (as strings). """ style = dict(self.styleDefaults) currentStyle = self.get("style") if currentStyle is not None: style.update(PlotStyle.toDict(currentStyle)) return style
def checkStyleProperties(self): """Verify that all properties currently requested in the C{style} attribute are in the legal C{styleProperties} list. @raise PmmlValidationError: If the list contains an unrecognized style property name, raise an error. Otherwise, silently pass. """ style = self.get("style") if style is not None: for name in PlotStyle.toDict(style).keys(): if name not in self.styleProperties: raise defs.PmmlValidationError( "Unrecognized style property: \"%s\"" % name)
def getStyleState(self): """Get the current state of the style (including any unmodified defaults) as a dictionary. @rtype: dict @return: Dictionary mapping style property names to their values (as strings). """ style = dict(self.styleDefaults) currentStyle = self.get("style") if currentStyle is not None: style.update(PlotStyle.toDict(currentStyle)) return style
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 performanceTable.begin("PlotGuideLines draw") output = svg.g() for directive in self.xpath("pmml:PlotVerticalLines | pmml:PlotHorizontalLines | pmml:PlotLine"): style = dict(self.styleDefaults) currentStyle = directive.get("style") if currentStyle is not None: style.update(PlotStyle.toDict(currentStyle)) style["fill"] = "none" style = PlotStyle.toString(style) if directive.hasTag("PlotVerticalLines"): try: x0 = plotCoordinates.xfieldType.stringToValue(directive["x0"]) except ValueError: raise defs.PmmlValidationError("Invalid x0: %r" % directive["x0"]) spacing = float(directive["spacing"]) low = plotCoordinates.innerX1 high = plotCoordinates.innerX2 up = list(NP("arange", x0, high, spacing, dtype=NP.dtype(float))) down = list(NP("arange", x0 - spacing, low, -spacing, dtype=NP.dtype(float))) for x in up + down: x1, y1 = x, float("-inf") X1, Y1 = plotCoordinates(x1, y1) x2, y2 = x, float("inf") X2, Y2 = plotCoordinates(x2, y2) output.append(svg.path(d="M %r %r L %r %r" % (X1, Y1, X2, Y2), style=style)) elif directive.hasTag("PlotHorizontalLines"): try: y0 = plotCoordinates.xfieldType.stringToValue(directive["y0"]) except ValueError: raise defs.PmmlValidationError("Invalid y0: %r" % directive["y0"]) spacing = float(directive["spacing"]) low = plotCoordinates.innerY1 high = plotCoordinates.innerY2 up = list(NP("arange", y0, high, spacing, dtype=NP.dtype(float))) down = list(NP("arange", y0 - spacing, low, -spacing, dtype=NP.dtype(float))) for y in up + down: x1, y1 = float("-inf"), y X1, Y1 = plotCoordinates(x1, y1) x2, y2 = float("inf"), y X2, Y2 = plotCoordinates(x2, y2) output.append(svg.path(d="M %r %r L %r %r" % (X1, Y1, X2, Y2), style=style)) elif directive.hasTag("PlotLine"): try: x1 = plotCoordinates.xfieldType.stringToValue(directive["x1"]) y1 = plotCoordinates.xfieldType.stringToValue(directive["y1"]) x2 = plotCoordinates.xfieldType.stringToValue(directive["x2"]) y2 = plotCoordinates.xfieldType.stringToValue(directive["y2"]) except ValueError: raise defs.PmmlValidationError("Invalid x1, y1, x2, or y2: %r %r %r %r" % (directive["x1"], directive["y1"], directive["x2"], directive["y2"])) X1, Y1 = plotCoordinates(x1, y1) X2, Y2 = plotCoordinates(x2, y2) output.append(svg.path(d="M %r %r L %r %r" % (X1, Y1, X2, Y2), style=style)) svgId = self.get("svgId") if svgId is not None: output["id"] = svgId performanceTable.end("PlotGuideLines draw") return output
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 performanceTable.begin("PlotHistogram draw") cumulative = self.get("cumulative", defaultFromXsd=True, convertType=True) vertical = self.get("vertical", defaultFromXsd=True, convertType=True) visualization = self.get("visualization", defaultFromXsd=True) output = svg.g() if len(state.count) > 0: if state.fieldType is not self.fieldTypeNumeric: if vertical: strings = plotCoordinates.xstrings else: strings = plotCoordinates.ystrings newCount = [] for string in strings: try: index = state.edges.index(string) except ValueError: newCount.append(0.0) else: newCount.append(state.count[index]) state.count = newCount state.edges = [(i - 0.5, i + 0.5) for i in xrange(len(strings))] if vertical: Ax = NP("array", [ low if low is not None else float("-inf") for low, high in state.edges ], dtype=NP.dtype(float)) Bx = NP(Ax.copy()) Cx = NP("array", [ high if high is not None else float("inf") for low, high in state.edges ], dtype=NP.dtype(float)) Dx = NP(Cx.copy()) Ay = NP("zeros", len(state.count), dtype=NP.dtype(float)) if cumulative: Cy = NP("cumsum", NP("array", state.count, dtype=NP.dtype(float))) By = NP("roll", Cy, 1) By[0] = 0.0 else: By = NP("array", state.count, dtype=NP.dtype(float)) Cy = NP(By.copy()) Dy = NP(Ay.copy()) else: if cumulative: Cx = NP("cumsum", NP("array", state.count, dtype=NP.dtype(float))) Bx = NP("roll", Cx, 1) Bx[0] = 0.0 else: Bx = NP("array", state.count, dtype=NP.dtype(float)) Cx = NP(Bx.copy()) Ax = NP("zeros", len(state.count), dtype=NP.dtype(float)) Dx = NP(Ax.copy()) Ay = NP("array", [ low if low is not None else float("-inf") for low, high in state.edges ], dtype=NP.dtype(float)) By = NP(Ay.copy()) Cy = NP("array", [ high if high is not None else float("inf") for low, high in state.edges ], dtype=NP.dtype(float)) Dy = NP(Cy.copy()) AX, AY = plotCoordinates(Ax, Ay) BX, BY = plotCoordinates(Bx, By) CX, CY = plotCoordinates(Cx, Cy) DX, DY = plotCoordinates(Dx, Dy) if visualization == "skyline": gap = self.get("gap", defaultFromXsd=True, convertType=True) if vertical: if gap > 0.0 and NP( NP(DX - gap / 2.0) - NP(AX + gap / 2.0)).min() > 0.0: AX += gap / 2.0 BX += gap / 2.0 CX -= gap / 2.0 DX -= gap / 2.0 else: if gap > 0.0 and NP( NP(AY + gap / 2.0) - NP(DY - gap / 2.0)).min() > 0.0: AY -= gap / 2.0 BY -= gap / 2.0 CY += gap / 2.0 DY += gap / 2.0 pathdata = [] nextIsMoveto = True for i in xrange(len(state.count)): iprev = i - 1 inext = i + 1 if vertical and By[i] == 0.0 and Cy[i] == 0.0: if i > 0 and not nextIsMoveto: pathdata.append("L %r %r" % (DX[iprev], DY[iprev])) nextIsMoveto = True elif not vertical and Bx[i] == 0.0 and Cx[i] == 0.0: if i > 0 and not nextIsMoveto: pathdata.append("L %r %r" % (DX[iprev], DY[iprev])) nextIsMoveto = True else: if nextIsMoveto or gap > 0.0 or ( vertical and DX[iprev] != AX[i]) or ( not vertical and DY[iprev] != AY[i]): pathdata.append("M %r %r" % (AX[i], AY[i])) nextIsMoveto = False pathdata.append("L %r %r" % (BX[i], BY[i])) pathdata.append("L %r %r" % (CX[i], CY[i])) if i == len(state.count) - 1 or gap > 0.0 or ( vertical and DX[i] != AX[inext]) or ( not vertical and DY[i] != AY[inext]): pathdata.append("L %r %r" % (DX[i], DY[i])) style = self.getStyleState() del style["marker-size"] del style["marker-outline"] output.append( svg.path(d=" ".join(pathdata), style=PlotStyle.toString(style))) elif visualization == "polyline": pathdata = [] for i in xrange(len(state.count)): if i == 0: pathdata.append("M %r %r" % (AX[i], AY[i])) pathdata.append("L %r %r" % ((BX[i] + CX[i]) / 2.0, (BY[i] + CY[i]) / 2.0)) if i == len(state.count) - 1: pathdata.append("L %r %r" % (DX[i], DY[i])) style = self.getStyleState() del style["marker-size"] del style["marker-outline"] output.append( svg.path(d=" ".join(pathdata), style=PlotStyle.toString(style))) elif visualization == "smooth": smoothingSamples = math.ceil(len(state.count) / 2.0) BCX = NP(NP(BX + CX) / 2.0) BCY = NP(NP(BY + CY) / 2.0) xarray = NP("array", [AX[0]] + list(BCX) + [DX[-1]], dtype=NP.dtype(float)) yarray = NP("array", [AY[0]] + list(BCY) + [DY[-1]], dtype=NP.dtype(float)) samples = NP("linspace", AX[0], DX[-1], int(smoothingSamples), endpoint=True) smoothingScale = abs(DX[-1] - AX[0]) / smoothingSamples xlist, ylist, dxlist, dylist = PlotCurve.pointsToSmoothCurve( xarray, yarray, samples, smoothingScale, False) pathdata = PlotCurve.formatPathdata(xlist, ylist, dxlist, dylist, PlotCoordinates(), False, True) style = self.getStyleState() fillStyle = dict( (x, style[x]) for x in style if x.startswith("fill")) fillStyle["stroke"] = "none" strokeStyle = dict( (x, style[x]) for x in style if x.startswith("stroke")) if style["fill"] != "none" and len(pathdata) > 0: if vertical: firstPoint = plotCoordinates(Ax[0], 0.0) lastPoint = plotCoordinates(Dx[-1], 0.0) else: firstPoint = plotCoordinates(0.0, Ay[0]) lastPoint = plotCoordinates(0.0, Dy[-1]) pathdata2 = [ "M %r %r" % firstPoint, pathdata[0].replace("M", "L") ] pathdata2.extend(pathdata[1:]) pathdata2.append(pathdata[-1]) pathdata2.append("L %r %r" % lastPoint) output.append( svg.path(d=" ".join(pathdata2), style=PlotStyle.toString(fillStyle))) output.append( svg.path(d=" ".join(pathdata), style=PlotStyle.toString(strokeStyle))) elif visualization == "points": currentStyle = PlotStyle.toDict(self.get("style") or {}) style = self.getStyleState() if "fill" not in currentStyle: style["fill"] = "black" BCX = NP(NP(BX + CX) / 2.0) BCY = NP(NP(BY + CY) / 2.0) svgId = self.get("svgId") if svgId is None: svgIdMarker = plotDefinitions.uniqueName() else: svgIdMarker = svgId + ".marker" marker = PlotScatter.makeMarker( svgIdMarker, self.get("marker", defaultFromXsd=True), style, self.childOfTag("PlotSvgMarker")) plotDefinitions[marker.get("id")] = marker markerReference = "#" + marker.get("id") output.extend( svg.use( **{ "x": repr(x), "y": repr(y), defs.XLINK_HREF: markerReference }) for x, y in itertools.izip(BCX, BCY)) else: raise NotImplementedError("TODO: add 'errorbars'") svgId = self.get("svgId") if svgId is not None: output["id"] = svgId performanceTable.end("PlotHistogram draw") return output
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 performanceTable.begin("PlotGuideLines draw") output = svg.g() for directive in self.xpath( "pmml:PlotVerticalLines | pmml:PlotHorizontalLines | pmml:PlotLine" ): style = dict(self.styleDefaults) currentStyle = directive.get("style") if currentStyle is not None: style.update(PlotStyle.toDict(currentStyle)) style["fill"] = "none" style = PlotStyle.toString(style) if directive.hasTag("PlotVerticalLines"): try: x0 = plotCoordinates.xfieldType.stringToValue( directive["x0"]) except ValueError: raise defs.PmmlValidationError("Invalid x0: %r" % directive["x0"]) spacing = float(directive["spacing"]) low = plotCoordinates.innerX1 high = plotCoordinates.innerX2 up = list( NP("arange", x0, high, spacing, dtype=NP.dtype(float))) down = list( NP("arange", x0 - spacing, low, -spacing, dtype=NP.dtype(float))) for x in up + down: x1, y1 = x, float("-inf") X1, Y1 = plotCoordinates(x1, y1) x2, y2 = x, float("inf") X2, Y2 = plotCoordinates(x2, y2) output.append( svg.path(d="M %r %r L %r %r" % (X1, Y1, X2, Y2), style=style)) elif directive.hasTag("PlotHorizontalLines"): try: y0 = plotCoordinates.xfieldType.stringToValue( directive["y0"]) except ValueError: raise defs.PmmlValidationError("Invalid y0: %r" % directive["y0"]) spacing = float(directive["spacing"]) low = plotCoordinates.innerY1 high = plotCoordinates.innerY2 up = list( NP("arange", y0, high, spacing, dtype=NP.dtype(float))) down = list( NP("arange", y0 - spacing, low, -spacing, dtype=NP.dtype(float))) for y in up + down: x1, y1 = float("-inf"), y X1, Y1 = plotCoordinates(x1, y1) x2, y2 = float("inf"), y X2, Y2 = plotCoordinates(x2, y2) output.append( svg.path(d="M %r %r L %r %r" % (X1, Y1, X2, Y2), style=style)) elif directive.hasTag("PlotLine"): try: x1 = plotCoordinates.xfieldType.stringToValue( directive["x1"]) y1 = plotCoordinates.xfieldType.stringToValue( directive["y1"]) x2 = plotCoordinates.xfieldType.stringToValue( directive["x2"]) y2 = plotCoordinates.xfieldType.stringToValue( directive["y2"]) except ValueError: raise defs.PmmlValidationError( "Invalid x1, y1, x2, or y2: %r %r %r %r" % (directive["x1"], directive["y1"], directive["x2"], directive["y2"])) X1, Y1 = plotCoordinates(x1, y1) X2, Y2 = plotCoordinates(x2, y2) output.append( svg.path(d="M %r %r L %r %r" % (X1, Y1, X2, Y2), style=style)) svgId = self.get("svgId") if svgId is not None: output["id"] = svgId performanceTable.end("PlotGuideLines draw") return output
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 performanceTable.begin("PlotHistogram draw") cumulative = self.get("cumulative", defaultFromXsd=True, convertType=True) vertical = self.get("vertical", defaultFromXsd=True, convertType=True) visualization = self.get("visualization", defaultFromXsd=True) output = svg.g() if len(state.count) > 0: if state.fieldType is not self.fieldTypeNumeric: if vertical: strings = plotCoordinates.xstrings else: strings = plotCoordinates.ystrings newCount = [] for string in strings: try: index = state.edges.index(string) except ValueError: newCount.append(0.0) else: newCount.append(state.count[index]) state.count = newCount state.edges = [(i - 0.5, i + 0.5) for i in xrange(len(strings))] if vertical: Ax = NP("array", [low if low is not None else float("-inf") for low, high in state.edges], dtype=NP.dtype(float)) Bx = NP(Ax.copy()) Cx = NP("array", [high if high is not None else float("inf") for low, high in state.edges], dtype=NP.dtype(float)) Dx = NP(Cx.copy()) Ay = NP("zeros", len(state.count), dtype=NP.dtype(float)) if cumulative: Cy = NP("cumsum", NP("array", state.count, dtype=NP.dtype(float))) By = NP("roll", Cy, 1) By[0] = 0.0 else: By = NP("array", state.count, dtype=NP.dtype(float)) Cy = NP(By.copy()) Dy = NP(Ay.copy()) else: if cumulative: Cx = NP("cumsum", NP("array", state.count, dtype=NP.dtype(float))) Bx = NP("roll", Cx, 1) Bx[0] = 0.0 else: Bx = NP("array", state.count, dtype=NP.dtype(float)) Cx = NP(Bx.copy()) Ax = NP("zeros", len(state.count), dtype=NP.dtype(float)) Dx = NP(Ax.copy()) Ay = NP("array", [low if low is not None else float("-inf") for low, high in state.edges], dtype=NP.dtype(float)) By = NP(Ay.copy()) Cy = NP("array", [high if high is not None else float("inf") for low, high in state.edges], dtype=NP.dtype(float)) Dy = NP(Cy.copy()) AX, AY = plotCoordinates(Ax, Ay) BX, BY = plotCoordinates(Bx, By) CX, CY = plotCoordinates(Cx, Cy) DX, DY = plotCoordinates(Dx, Dy) if visualization == "skyline": gap = self.get("gap", defaultFromXsd=True, convertType=True) if vertical: if gap > 0.0 and NP(NP(DX - gap/2.0) - NP(AX + gap/2.0)).min() > 0.0: AX += gap/2.0 BX += gap/2.0 CX -= gap/2.0 DX -= gap/2.0 else: if gap > 0.0 and NP(NP(AY + gap/2.0) - NP(DY - gap/2.0)).min() > 0.0: AY -= gap/2.0 BY -= gap/2.0 CY += gap/2.0 DY += gap/2.0 pathdata = [] nextIsMoveto = True for i in xrange(len(state.count)): iprev = i - 1 inext = i + 1 if vertical and By[i] == 0.0 and Cy[i] == 0.0: if i > 0 and not nextIsMoveto: pathdata.append("L %r %r" % (DX[iprev], DY[iprev])) nextIsMoveto = True elif not vertical and Bx[i] == 0.0 and Cx[i] == 0.0: if i > 0 and not nextIsMoveto: pathdata.append("L %r %r" % (DX[iprev], DY[iprev])) nextIsMoveto = True else: if nextIsMoveto or gap > 0.0 or (vertical and DX[iprev] != AX[i]) or (not vertical and DY[iprev] != AY[i]): pathdata.append("M %r %r" % (AX[i], AY[i])) nextIsMoveto = False pathdata.append("L %r %r" % (BX[i], BY[i])) pathdata.append("L %r %r" % (CX[i], CY[i])) if i == len(state.count) - 1 or gap > 0.0 or (vertical and DX[i] != AX[inext]) or (not vertical and DY[i] != AY[inext]): pathdata.append("L %r %r" % (DX[i], DY[i])) style = self.getStyleState() del style["marker-size"] del style["marker-outline"] output.append(svg.path(d=" ".join(pathdata), style=PlotStyle.toString(style))) elif visualization == "polyline": pathdata = [] for i in xrange(len(state.count)): if i == 0: pathdata.append("M %r %r" % (AX[i], AY[i])) pathdata.append("L %r %r" % ((BX[i] + CX[i])/2.0, (BY[i] + CY[i])/2.0)) if i == len(state.count) - 1: pathdata.append("L %r %r" % (DX[i], DY[i])) style = self.getStyleState() del style["marker-size"] del style["marker-outline"] output.append(svg.path(d=" ".join(pathdata), style=PlotStyle.toString(style))) elif visualization == "smooth": smoothingSamples = math.ceil(len(state.count) / 2.0) BCX = NP(NP(BX + CX) / 2.0) BCY = NP(NP(BY + CY) / 2.0) xarray = NP("array", [AX[0]] + list(BCX) + [DX[-1]], dtype=NP.dtype(float)) yarray = NP("array", [AY[0]] + list(BCY) + [DY[-1]], dtype=NP.dtype(float)) samples = NP("linspace", AX[0], DX[-1], int(smoothingSamples), endpoint=True) smoothingScale = abs(DX[-1] - AX[0]) / smoothingSamples xlist, ylist, dxlist, dylist = PlotCurve.pointsToSmoothCurve(xarray, yarray, samples, smoothingScale, False) pathdata = PlotCurve.formatPathdata(xlist, ylist, dxlist, dylist, PlotCoordinates(), False, True) style = self.getStyleState() fillStyle = dict((x, style[x]) for x in style if x.startswith("fill")) fillStyle["stroke"] = "none" strokeStyle = dict((x, style[x]) for x in style if x.startswith("stroke")) if style["fill"] != "none" and len(pathdata) > 0: if vertical: firstPoint = plotCoordinates(Ax[0], 0.0) lastPoint = plotCoordinates(Dx[-1], 0.0) else: firstPoint = plotCoordinates(0.0, Ay[0]) lastPoint = plotCoordinates(0.0, Dy[-1]) pathdata2 = ["M %r %r" % firstPoint, pathdata[0].replace("M", "L")] pathdata2.extend(pathdata[1:]) pathdata2.append(pathdata[-1]) pathdata2.append("L %r %r" % lastPoint) output.append(svg.path(d=" ".join(pathdata2), style=PlotStyle.toString(fillStyle))) output.append(svg.path(d=" ".join(pathdata), style=PlotStyle.toString(strokeStyle))) elif visualization == "points": currentStyle = PlotStyle.toDict(self.get("style") or {}) style = self.getStyleState() if "fill" not in currentStyle: style["fill"] = "black" BCX = NP(NP(BX + CX) / 2.0) BCY = NP(NP(BY + CY) / 2.0) svgId = self.get("svgId") if svgId is None: svgIdMarker = plotDefinitions.uniqueName() else: svgIdMarker = svgId + ".marker" marker = PlotScatter.makeMarker(svgIdMarker, self.get("marker", defaultFromXsd=True), style, self.childOfTag("PlotSvgMarker")) plotDefinitions[marker.get("id")] = marker markerReference = "#" + marker.get("id") output.extend(svg.use(**{"x": repr(x), "y": repr(y), defs.XLINK_HREF: markerReference}) for x, y in itertools.izip(BCX, BCY)) else: raise NotImplementedError("TODO: add 'errorbars'") svgId = self.get("svgId") if svgId is not None: output["id"] = svgId performanceTable.end("PlotHistogram draw") return output