Example #1
0
    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
Example #2
0
    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)
Example #3
0
    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)
Example #4
0
    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)
Example #5
0
    def draw(self, dataTable, functionTable, performanceTable, plotCoordinates,
             plotContentBox, plotDefinitions):
        """Draw the plot annotation.

        @type dataTable: DataTable
        @param dataTable: Contains the data to plot, if any.
        @type functionTable: FunctionTable
        @param functionTable: Defines functions that may be used to transform data for plotting.
        @type performanceTable: PerformanceTable
        @param performanceTable: Measures and records performance (time and memory consumption) of the drawing process.
        @type plotCoordinates: PlotCoordinates
        @param plotCoordinates: The coordinate system in which this plot will be placed.
        @type plotContentBox: PlotContentBox
        @param plotContentBox: A bounding box in which this plot will be placed.
        @type plotDefinitions: PlotDefinitions
        @type plotDefinitions: The dictionary of key-value pairs that forms the <defs> section of the SVG document.
        @rtype: SvgBinding
        @return: An SVG fragment representing the fully drawn plot.
        """

        svg = SvgBinding.elementMaker

        svgId = self.get("svgId")
        if svgId is None:
            output = svg.g()
        else:
            output = svg.g(**{"id": svgId})
        content = [output]

        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(
                "PlotSvgAnnotation should specify an inline SVG or a fileName but not both or neither"
            )

        style = self.getStyleState()

        if style.get("margin-bottom") == "auto": del style["margin-bottom"]
        if style.get("margin-top") == "auto": del style["margin-top"]
        if style.get("margin-left") == "auto": del style["margin-left"]
        if style.get("margin-right") == "auto": del style["margin-right"]

        subContentBox = plotContentBox.subContent(style)
        sx1, sy1, sx2, sy2 = PlotSvgAnnotation.findSize(svgBinding)
        nominalHeight = sy2 - sy1
        nominalWidth = sx2 - sx1

        if nominalHeight < subContentBox.height:
            if "margin-bottom" in style and "margin-top" in style:
                pass
            elif "margin-bottom" in style:
                style["margin-top"] = subContentBox.height - nominalHeight
            elif "margin-top" in style:
                style["margin-bottom"] = subContentBox.height - nominalHeight
            else:
                style["margin-bottom"] = style["margin-top"] = (
                    subContentBox.height - nominalHeight) / 2.0

        if nominalWidth < subContentBox.width:
            if "margin-left" in style and "margin-right" in style:
                pass
            elif "margin-left" in style:
                style["margin-right"] = subContentBox.width - nominalWidth
            elif "margin-right" in style:
                style["margin-left"] = subContentBox.width - nominalWidth
            else:
                style["margin-left"] = style["margin-right"] = (
                    subContentBox.width - nominalWidth) / 2.0

        subContentBox = plotContentBox.subContent(style)
        borderRect = plotContentBox.border(style)

        if subContentBox is not None:
            tx1, ty1 = plotCoordinates(subContentBox.x, subContentBox.y)
            tx2, ty2 = plotCoordinates(subContentBox.x + subContentBox.width,
                                       subContentBox.y + subContentBox.height)

            output.extend([copy.deepcopy(x) for x in svgBinding.getchildren()])

            output["transform"] = "translate(%r, %r) scale(%r, %r)" % (
                tx1 - sx1, ty1 - sy1, (tx2 - tx1) / float(sx2 - sx1),
                (ty2 - ty1) / float(sy2 - sy1))

        if borderRect is not None:
            rectStyle = {"stroke": style["border-color"]}
            if rectStyle["stroke"] != "none":
                for styleProperty in "border-dasharray", "border-dashoffset", "border-linecap", "border-linejoin", "border-miterlimit", "border-opacity", "border-width":
                    if styleProperty in style:
                        rectStyle[styleProperty.replace(
                            "border-", "stroke-")] = style[styleProperty]

                x1 = borderRect.x
                y1 = borderRect.y
                x2 = borderRect.x + borderRect.width
                y2 = borderRect.y + borderRect.height
                x1, y1 = plotCoordinates(x1, y1)
                x2, y2 = plotCoordinates(x2, y2)

                subAttrib = {
                    "x": repr(x1),
                    "y": repr(y1),
                    "width": repr(x2 - x1),
                    "height": repr(y2 - y1),
                    "style": PlotStyle.toString(rectStyle)
                }

                subAttrib["style"] = PlotStyle.toString(rectStyle)
                if svgId is not None:
                    subAttrib["id"] = svgId + ".border"
                content.append(svg.rect(**subAttrib))

        return svg.g(*content)
    def draw(self, dataTable, functionTable, performanceTable, plotCoordinates, plotContentBox, plotDefinitions):
        """Draw the plot annotation.

        @type dataTable: DataTable
        @param dataTable: Contains the data to plot, if any.
        @type functionTable: FunctionTable
        @param functionTable: Defines functions that may be used to transform data for plotting.
        @type performanceTable: PerformanceTable
        @param performanceTable: Measures and records performance (time and memory consumption) of the drawing process.
        @type plotCoordinates: PlotCoordinates
        @param plotCoordinates: The coordinate system in which this plot will be placed.
        @type plotContentBox: PlotContentBox
        @param plotContentBox: A bounding box in which this plot will be placed.
        @type plotDefinitions: PlotDefinitions
        @type plotDefinitions: The dictionary of key-value pairs that forms the <defs> section of the SVG document.
        @rtype: SvgBinding
        @return: An SVG fragment representing the fully drawn plot.
        """

        svg = SvgBinding.elementMaker

        svgId = self.get("svgId")
        if svgId is None:
            output = svg.g()
        else:
            output = svg.g(**{"id": svgId})
        content = [output]

        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(
                "PlotSvgAnnotation should specify an inline SVG or a fileName but not both or neither"
            )

        style = self.getStyleState()

        if style.get("margin-bottom") == "auto":
            del style["margin-bottom"]
        if style.get("margin-top") == "auto":
            del style["margin-top"]
        if style.get("margin-left") == "auto":
            del style["margin-left"]
        if style.get("margin-right") == "auto":
            del style["margin-right"]

        subContentBox = plotContentBox.subContent(style)
        sx1, sy1, sx2, sy2 = PlotSvgAnnotation.findSize(svgBinding)
        nominalHeight = sy2 - sy1
        nominalWidth = sx2 - sx1

        if nominalHeight < subContentBox.height:
            if "margin-bottom" in style and "margin-top" in style:
                pass
            elif "margin-bottom" in style:
                style["margin-top"] = subContentBox.height - nominalHeight
            elif "margin-top" in style:
                style["margin-bottom"] = subContentBox.height - nominalHeight
            else:
                style["margin-bottom"] = style["margin-top"] = (subContentBox.height - nominalHeight) / 2.0

        if nominalWidth < subContentBox.width:
            if "margin-left" in style and "margin-right" in style:
                pass
            elif "margin-left" in style:
                style["margin-right"] = subContentBox.width - nominalWidth
            elif "margin-right" in style:
                style["margin-left"] = subContentBox.width - nominalWidth
            else:
                style["margin-left"] = style["margin-right"] = (subContentBox.width - nominalWidth) / 2.0

        subContentBox = plotContentBox.subContent(style)
        borderRect = plotContentBox.border(style)

        if subContentBox is not None:
            tx1, ty1 = plotCoordinates(subContentBox.x, subContentBox.y)
            tx2, ty2 = plotCoordinates(subContentBox.x + subContentBox.width, subContentBox.y + subContentBox.height)

            output.extend([copy.deepcopy(x) for x in svgBinding.getchildren()])

            output["transform"] = "translate(%r, %r) scale(%r, %r)" % (
                tx1 - sx1,
                ty1 - sy1,
                (tx2 - tx1) / float(sx2 - sx1),
                (ty2 - ty1) / float(sy2 - sy1),
            )

        if borderRect is not None:
            rectStyle = {"stroke": style["border-color"]}
            if rectStyle["stroke"] != "none":
                for styleProperty in (
                    "border-dasharray",
                    "border-dashoffset",
                    "border-linecap",
                    "border-linejoin",
                    "border-miterlimit",
                    "border-opacity",
                    "border-width",
                ):
                    if styleProperty in style:
                        rectStyle[styleProperty.replace("border-", "stroke-")] = style[styleProperty]

                x1 = borderRect.x
                y1 = borderRect.y
                x2 = borderRect.x + borderRect.width
                y2 = borderRect.y + borderRect.height
                x1, y1 = plotCoordinates(x1, y1)
                x2, y2 = plotCoordinates(x2, y2)

                subAttrib = {
                    "x": repr(x1),
                    "y": repr(y1),
                    "width": repr(x2 - x1),
                    "height": repr(y2 - y1),
                    "style": PlotStyle.toString(rectStyle),
                }

                subAttrib["style"] = PlotStyle.toString(rectStyle)
                if svgId is not None:
                    subAttrib["id"] = svgId + ".border"
                content.append(svg.rect(**subAttrib))

        return svg.g(*content)
Example #7
0
    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)