示例#1
0
 def sample5d():
     "Sample drawing, xvalue/yvalue axes, y connected at left of x."
     drawing = Drawing(400, 200)
     data = [(10, 20, 30, 42)]
     xAxis = XValueAxis()
     xAxis.setPosition(50, 50, 300)
     xAxis.configure(data)
     yAxis = YValueAxis()
     yAxis.setPosition(50, 50, 125)
     yAxis.joinAxis = xAxis
     yAxis.joinAxisMode = 'left'
     yAxis.configure(data)
     drawing.add(xAxis)
     drawing.add(yAxis)
     return drawing
示例#2
0
    def __init__(self):
        PlotArea.__init__(self)
        self.reversePlotOrder = 0

        self.xValueAxis = XValueAxis()
        self.yValueAxis = YValueAxis()

        # this defines two series of 3 points.  Just an example.
        self.data = [((1, 1), (2, 2), (2.5, 1), (3, 3), (4, 5)), ((1, 2), (2, 3), (2.5, 2), (3, 4), (4, 6))]

        self.lines = TypedPropertyCollection(LinePlotProperties)
        self.lines.strokeWidth = 1
        self.lines[0].strokeColor = colors.red
        self.lines[1].strokeColor = colors.blue

        self.lineLabels = TypedPropertyCollection(Label)
        self.lineLabelFormat = None
        self.lineLabelArray = None

        # this says whether the origin is inside or outside
        # the bar - +10 means put the origin ten points
        # above the tip of the bar if value > 0, or ten
        # points inside if bar value < 0.  This is different
        # to label dx/dy which are not dependent on the
        # sign of the data.
        self.lineLabelNudge = 10
        # if you have multiple series, by default they butt
        # together.

        # New line chart attributes.
        self.joinedLines = 1  # Connect items with straight lines.

        # private attributes
        self._inFill = None
示例#3
0
    def make_x_axis(self, x_label, x_min, x_max, x_step):

        self._add(self,
                  Label(),
                  name='XLabel',
                  validate=None,
                  desc="The label on the horizontal axis")

        self.XLabel.fontName = 'Helvetica'
        self.XLabel.fontSize = 10
        self.XLabel.x = 22
        self.XLabel.y = 45
        self.XLabel.textAnchor = 'middle'
        self.XLabel.maxWidth = 500
        self.XLabel.height = 20
        self.XLabel._text = x_label

        self.chart.xValueAxis = XValueAxis()
        self.chart.xValueAxis.labels.boxAnchor = 'autox'
        self.chart.xValueAxis.valueMin = x_min
        self.chart.xValueAxis.valueMax = x_max
        self.chart.xValueAxis.valueStep = x_step
        self.chart.xValueAxis.labels.fontName = "Helvetica"
        self.chart.xValueAxis.labels.fontSize = 10
        self.chart.xValueAxis.visibleTicks = 1
        self.chart.xValueAxis.labels.rightPadding = 0
        self.chart.xValueAxis.labels.dx = 1
示例#4
0
 def sample7b():
     "Sample drawing, xvalue/ycat axes, y connected at left of x."
     drawing = Drawing(400, 200)
     data = [(10, 20, 30, 42)]
     xAxis = XValueAxis()
     xAxis._length = 300
     xAxis.configure(data)
     yAxis = YCategoryAxis()
     yAxis.setPosition(50, 50, 125)
     yAxis.joinAxis = xAxis
     yAxis.joinAxisMode = 'left'
     yAxis.categoryNames = ['Beer', 'Wine', 'Meat', 'Cannelloni']
     yAxis.labels.boxAnchor = 'e'
     yAxis.configure(data)
     drawing.add(xAxis)
     drawing.add(yAxis)
     return drawing
示例#5
0
    def makeTickLabels(self):
        g = XValueAxis.makeTickLabels(self)

        desc_text = make_desc_test(self, "X")
        if desc_text is not None:
            g.add(desc_text)

        return g
 def sample7b():
     "Sample drawing, xvalue/ycat axes, y connected at left of x."
     drawing = Drawing(400, 200)
     data = [(10, 20, 30, 42)]
     xAxis = XValueAxis()
     xAxis._length = 300
     xAxis.configure(data)
     yAxis = YCategoryAxis()
     yAxis.setPosition(50, 50, 125)
     yAxis.joinAxis = xAxis
     yAxis.joinAxisMode = 'left'
     yAxis.categoryNames = ['Beer', 'Wine', 'Meat', 'Cannelloni']
     yAxis.labels.boxAnchor = 'e'
     yAxis.configure(data)
     drawing.add(xAxis)
     drawing.add(yAxis)
     return drawing
示例#7
0
    def __init__(self):
        PlotArea.__init__(self)
        self.reversePlotOrder = 0

        self.xValueAxis = XValueAxis()
        self.yValueAxis = YValueAxis()

        # this defines two series of 3 points.  Just an example.
        self.data = [
            ((1,1), (2,2), (2.5,1), (3,3), (4,5)),
            ((1,2), (2,3), (2.5,2), (3,4), (4,6))
            ]

        self.lines = TypedPropertyCollection(LinePlotProperties)
        self.lines.strokeWidth = 1
        self.lines[0].strokeColor = colors.red
        self.lines[1].strokeColor = colors.blue

        self.lineLabels = TypedPropertyCollection(Label)
        self.lineLabelFormat = None
        self.lineLabelArray = None

        # this says whether the origin is inside or outside
        # the bar - +10 means put the origin ten points
        # above the tip of the bar if value > 0, or ten
        # points inside if bar value < 0.  This is different
        # to label dx/dy which are not dependent on the
        # sign of the data.
        self.lineLabelNudge = 10
        # if you have multiple series, by default they butt
        # together.

        # New line chart attributes.
        self.joinedLines = 1 # Connect items with straight lines.

        #private attributes
        self._inFill = None
        self.annotations = []
        self.behindAxes = 0
        self.gridFirst = 0
 def sample4c1():
     "xvalue/yvalue axes, without drawing axis lines/ticks."
     drawing = Drawing(400, 200)
     data = [(10, 20, 30, 42)]
     yAxis = YValueAxis()
     yAxis.setPosition(50, 50, 125)
     yAxis.configure(data)
     yAxis.visibleAxis = 0
     yAxis.visibleTicks = 0
     xAxis = XValueAxis()
     xAxis._length = 300
     xAxis.joinAxis = yAxis
     xAxis.joinAxisMode = 'bottom'
     xAxis.configure(data)
     xAxis.visibleAxis = 0
     xAxis.visibleTicks = 0
     drawing.add(xAxis)
     drawing.add(yAxis)
     return drawing
 def sample4b():
     "Sample drawing, xvalue/yvalue axes, y connected at value 35 of x."
     drawing = Drawing(400, 200)
     data = [(10, 20, 30, 42)]
     yAxis = YValueAxis()
     yAxis.setPosition(50, 50, 125)
     yAxis.configure(data)
     xAxis = XValueAxis()
     xAxis._length = 300
     xAxis.joinAxis = yAxis
     xAxis.joinAxisMode = 'value'
     xAxis.joinAxisPos = 35
     xAxis.configure(data)
     drawing.add(xAxis)
     drawing.add(yAxis)
     return drawing
示例#10
0
 def sample4c1():
     "xvalue/yvalue axes, without drawing axis lines/ticks."
     drawing = Drawing(400, 200)
     data = [(10, 20, 30, 42)]
     yAxis = YValueAxis()
     yAxis.setPosition(50, 50, 125)
     yAxis.configure(data)
     yAxis.visibleAxis = 0
     yAxis.visibleTicks = 0
     xAxis = XValueAxis()
     xAxis._length = 300
     xAxis.joinAxis = yAxis
     xAxis.joinAxisMode = 'bottom'
     xAxis.configure(data)
     xAxis.visibleAxis = 0
     xAxis.visibleTicks = 0
     drawing.add(xAxis)
     drawing.add(yAxis)
     return drawing
示例#11
0
 def sample4b():
     "Sample drawing, xvalue/yvalue axes, y connected at value 35 of x."
     drawing = Drawing(400, 200)
     data = [(10, 20, 30, 42)]
     yAxis = YValueAxis()
     yAxis.setPosition(50, 50, 125)
     yAxis.configure(data)
     xAxis = XValueAxis()
     xAxis._length = 300
     xAxis.joinAxis = yAxis
     xAxis.joinAxisMode = 'value'
     xAxis.joinAxisPos = 35
     xAxis.configure(data)
     drawing.add(xAxis)
     drawing.add(yAxis)
     return drawing
 def sample5d():
     "Sample drawing, xvalue/yvalue axes, y connected at left of x."
     drawing = Drawing(400, 200)
     data = [(10, 20, 30, 42)]
     xAxis = XValueAxis()
     xAxis.setPosition(50, 50, 300)
     xAxis.configure(data)
     yAxis = YValueAxis()
     yAxis.setPosition(50, 50, 125)
     yAxis.joinAxis = xAxis
     yAxis.joinAxisMode = 'left'
     yAxis.configure(data)
     drawing.add(xAxis)
     drawing.add(yAxis)
     return drawing
示例#13
0
class LinePlot(PlotArea):
    """Line plot with multiple lines.

    Both x- and y-axis are value axis (so there are no seperate
    X and Y versions of this class).
    """

    _attrMap = AttrMap(
        BASE=PlotArea,
        reversePlotOrder=AttrMapValue(isBoolean, desc="If true reverse plot order."),
        lineLabelNudge=AttrMapValue(isNumber, desc="Distance between a data point and its label."),
        lineLabels=AttrMapValue(None, desc="Handle to the list of data point labels."),
        lineLabelFormat=AttrMapValue(None, desc="Formatting string or function used for data point labels."),
        lineLabelArray=AttrMapValue(
            None, desc="explicit array of line label values, must match size of data if present."
        ),
        joinedLines=AttrMapValue(isNumber, desc="Display data points joined with lines if true."),
        strokeColor=AttrMapValue(isColorOrNone, desc="Color used for background border of plot area."),
        fillColor=AttrMapValue(isColorOrNone, desc="Color used for background interior of plot area."),
        lines=AttrMapValue(None, desc="Handle of the lines."),
        xValueAxis=AttrMapValue(None, desc="Handle of the x axis."),
        yValueAxis=AttrMapValue(None, desc="Handle of the y axis."),
        data=AttrMapValue(None, desc="Data to be plotted, list of (lists of) x/y tuples."),
        annotations=AttrMapValue(None, desc="list of callables, will be called with self, xscale, yscale."),
    )

    def __init__(self):
        PlotArea.__init__(self)
        self.reversePlotOrder = 0

        self.xValueAxis = XValueAxis()
        self.yValueAxis = YValueAxis()

        # this defines two series of 3 points.  Just an example.
        self.data = [((1, 1), (2, 2), (2.5, 1), (3, 3), (4, 5)), ((1, 2), (2, 3), (2.5, 2), (3, 4), (4, 6))]

        self.lines = TypedPropertyCollection(LinePlotProperties)
        self.lines.strokeWidth = 1
        self.lines[0].strokeColor = colors.red
        self.lines[1].strokeColor = colors.blue

        self.lineLabels = TypedPropertyCollection(Label)
        self.lineLabelFormat = None
        self.lineLabelArray = None

        # this says whether the origin is inside or outside
        # the bar - +10 means put the origin ten points
        # above the tip of the bar if value > 0, or ten
        # points inside if bar value < 0.  This is different
        # to label dx/dy which are not dependent on the
        # sign of the data.
        self.lineLabelNudge = 10
        # if you have multiple series, by default they butt
        # together.

        # New line chart attributes.
        self.joinedLines = 1  # Connect items with straight lines.

        # private attributes
        self._inFill = None

    def demo(self):
        """Shows basic use of a line chart."""

        drawing = Drawing(400, 200)

        data = [((1, 1), (2, 2), (2.5, 1), (3, 3), (4, 5)), ((1, 2), (2, 3), (2.5, 2), (3.5, 5), (4, 6))]

        lp = LinePlot()

        lp.x = 50
        lp.y = 50
        lp.height = 125
        lp.width = 300
        lp.data = data
        lp.joinedLines = 1
        lp.lineLabelFormat = "%2.0f"
        lp.strokeColor = colors.black

        lp.lines[0].strokeColor = colors.red
        lp.lines[0].symbol = makeMarker("FilledCircle")
        lp.lines[1].strokeColor = colors.blue
        lp.lines[1].symbol = makeMarker("FilledDiamond")

        lp.xValueAxis.valueMin = 0
        lp.xValueAxis.valueMax = 5
        lp.xValueAxis.valueStep = 1

        lp.yValueAxis.valueMin = 0
        lp.yValueAxis.valueMax = 7
        lp.yValueAxis.valueStep = 1

        drawing.add(lp)

        return drawing

    def calcPositions(self):
        """Works out where they go.

        Sets an attribute _positions which is a list of
        lists of (x, y) matching the data.
        """

        self._seriesCount = len(self.data)
        self._rowLength = max(map(len, self.data))

        self._positions = []
        for rowNo in range(len(self.data)):
            line = []
            for colNo in range(len(self.data[rowNo])):
                datum = self.data[rowNo][colNo]  # x,y value
                if type(datum[0]) == type(""):
                    x = self.xValueAxis.scale(mktime(mkTimeTuple(datum[0])))
                else:
                    x = self.xValueAxis.scale(datum[0])
                y = self.yValueAxis.scale(datum[1])
                line.append((x, y))
            self._positions.append(line)

    def _innerDrawLabel(self, rowNo, colNo, x, y):
        "Draw a label for a given item in the list."

        labelFmt = self.lineLabelFormat
        labelValue = self.data[rowNo][colNo][1]  ###

        if labelFmt is None:
            labelText = None
        elif type(labelFmt) is StringType:
            if labelFmt == "values":
                labelText = self.lineLabelArray[rowNo][colNo]
            else:
                labelText = labelFmt % labelValue
        elif type(labelFmt) is FunctionType:
            labelText = labelFmt(labelValue)
        elif isinstance(labelFmt, Formatter):
            labelText = labelFmt(labelValue)
        else:
            msg = "Unknown formatter type %s, expected string or function"
            raise Exception, msg % labelFmt

        if labelText:
            label = self.lineLabels[(rowNo, colNo)]
            # hack to make sure labels are outside the bar
            if y > 0:
                label.setOrigin(x, y + self.lineLabelNudge)
            else:
                label.setOrigin(x, y - self.lineLabelNudge)
            label.setText(labelText)
        else:
            label = None
        return label

    def drawLabel(self, G, rowNo, colNo, x, y):
        """Draw a label for a given item in the list.
        G must have an add method"""
        G.add(self._innerDrawLabel(rowNo, colNo, x, y))

    def makeLines(self):
        g = Group()
        bubblePlot = getattr(self, "_bubblePlot", None)
        if bubblePlot:
            yA = self.yValueAxis
            xA = self.xValueAxis
            bubbleR = min(yA._bubbleRadius, xA._bubbleRadius)
            bubbleMax = xA._bubbleMax

        labelFmt = self.lineLabelFormat

        P = range(len(self._positions))
        if self.reversePlotOrder:
            P.reverse()
        inFill = getattr(self, "_inFill", None)
        if inFill:
            inFillY = self.xValueAxis._y
            inFillX0 = self.yValueAxis._x
            inFillX1 = inFillX0 + self.xValueAxis._length
            inFillG = getattr(self, "_inFillG", g)
        # Iterate over data rows.
        styleCount = len(self.lines)
        for rowNo in P:
            row = self._positions[rowNo]
            rowStyle = self.lines[rowNo % styleCount]
            rowColor = rowStyle.strokeColor
            dash = getattr(rowStyle, "strokeDashArray", None)

            if hasattr(rowStyle, "strokeWidth"):
                width = rowStyle.strokeWidth
            elif hasattr(self.lines, "strokeWidth"):
                width = self.lines.strokeWidth
            else:
                width = None

            # Iterate over data columns.
            if self.joinedLines:
                points = []
                for xy in row:
                    points = points + [xy[0], xy[1]]
                if inFill:
                    points = points + [inFillX1, inFillY, inFillX0, inFillY]
                    filler = getattr(rowStyle, "filler", None)
                    if filler:
                        filler.fill(self, inFillG, rowNo, rowColor, points)
                    else:
                        inFillG.add(Polygon(points, fillColor=rowColor, strokeColor=rowColor, strokeWidth=0.1))
                else:
                    line = PolyLine(points, strokeColor=rowColor, strokeLineCap=0, strokeLineJoin=1)
                    if width:
                        line.strokeWidth = width
                    if dash:
                        line.strokeDashArray = dash
                    g.add(line)

            if hasattr(rowStyle, "symbol"):
                uSymbol = rowStyle.symbol
            elif hasattr(self.lines, "symbol"):
                uSymbol = self.lines.symbol
            else:
                uSymbol = None

            if uSymbol:
                j = -1
                if bubblePlot:
                    drow = self.data[rowNo]
                for xy in row:
                    j += 1
                    symbol = uSymbol2Symbol(uSymbol, xy[0], xy[1], rowColor)
                    if symbol:
                        if bubblePlot:
                            symbol.size = bubbleR * (drow[j][2] / bubbleMax) ** 0.5
                        g.add(symbol)

            # Draw data labels.
            for colNo in range(len(row)):
                x1, y1 = row[colNo]
                self.drawLabel(g, rowNo, colNo, x1, y1)

            shader = getattr(rowStyle, "shader", None)
            if shader:
                shader.shade(self, g, rowNo, rowColor, row)

        return g

    def makeSwatchSample(self, rowNo, x, y, width, height):
        styleCount = len(self.lines)
        styleIdx = rowNo % styleCount
        rowColor = self.lines[styleIdx].strokeColor

        if self.joinedLines:
            dash = getattr(self.lines[styleIdx], "strokeDashArray", getattr(self.lines, "strokeDashArray", None))
            strokeWidth = getattr(
                self.lines[styleIdx], "strokeWidth", getattr(self.lines[styleIdx], "strokeWidth", None)
            )
            L = Line(x, y, x + width, y + height, strokeColor=rowColor, strokeLineCap=0)
            if strokeWidth:
                L.strokeWidth = strokeWidth
            if dash:
                L.strokeDashArray = dash
        else:
            L = None

        if hasattr(self.lines[styleIdx], "symbol"):
            S = self.lines[styleIdx].symbol
        elif hasattr(self.lines, "symbol"):
            S = self.lines.symbol
        else:
            S = None

        if S:
            S = uSymbol2Symbol(S, x + width / 2.0, y + height / 2.0, rowColor)
        if S and L:
            g = Group()
            g.add(S)
            g.add(L)
            return g
        return S or L

    def draw(self):
        yA = self.yValueAxis
        xA = self.xValueAxis
        if getattr(self, "_bubblePlot", None):
            yA._bubblePlot = xA._bubblePlot = 1
        yA.setPosition(self.x, self.y, self.height)
        if yA:
            yA.joinAxis = xA
        if xA:
            xA.joinAxis = yA
        yA.configure(self.data)

        # if zero is in chart, put x axis there, otherwise use bottom.
        xAxisCrossesAt = yA.scale(0)
        if (xAxisCrossesAt > self.y + self.height) or (xAxisCrossesAt < self.y):
            y = self.y
        else:
            y = xAxisCrossesAt

        xA.setPosition(self.x, y, self.width)
        xA.configure(self.data)
        self.calcPositions()
        g = Group()
        g.add(self.makeBackground())
        if self._inFill:
            self._inFillG = Group()
            g.add(self._inFillG)
        g.add(xA)
        g.add(yA)
        yA.gridStart = xA._x
        yA.gridEnd = xA._x + xA._length
        xA.gridStart = yA._y
        xA.gridEnd = yA._y + yA._length
        xA.makeGrid(g, parent=self)
        yA.makeGrid(g, parent=self)
        g.add(self.makeLines())
        for a in getattr(self, "annotations", ()):
            g.add(a(self, xA.scale, yA.scale))
        return g
示例#14
0
class LinePlot(AbstractLineChart):
    """Line plot with multiple lines.

    Both x- and y-axis are value axis (so there are no seperate
    X and Y versions of this class).
    """
    _attrMap = AttrMap(BASE=PlotArea,
        reversePlotOrder = AttrMapValue(isBoolean, desc='If true reverse plot order.',advancedUsage=1),
        lineLabelNudge = AttrMapValue(isNumber, desc='Distance between a data point and its label.',advancedUsage=1),
        lineLabels = AttrMapValue(None, desc='Handle to the list of data point labels.'),
        lineLabelFormat = AttrMapValue(None, desc='Formatting string or function used for data point labels.'),
        lineLabelArray = AttrMapValue(None, desc='explicit array of line label values, must match size of data if present.'),
        joinedLines = AttrMapValue(isNumber, desc='Display data points joined with lines if true.'),
        strokeColor = AttrMapValue(isColorOrNone, desc='Color used for background border of plot area.'),
        fillColor = AttrMapValue(isColorOrNone, desc='Color used for background interior of plot area.'),
        lines = AttrMapValue(None, desc='Handle of the lines.'),
        xValueAxis = AttrMapValue(None, desc='Handle of the x axis.'),
        yValueAxis = AttrMapValue(None, desc='Handle of the y axis.'),
        data = AttrMapValue(None, desc='Data to be plotted, list of (lists of) x/y tuples.'),
        annotations = AttrMapValue(None, desc='list of callables, will be called with self, xscale, yscale.',advancedUsage=1),
        behindAxes = AttrMapValue(isBoolean, desc='If true use separate line group.',advancedUsage=1),
        gridFirst = AttrMapValue(isBoolean, desc='If true use draw grids before axes.',advancedUsage=1),
        )

    def __init__(self):
        PlotArea.__init__(self)
        self.reversePlotOrder = 0

        self.xValueAxis = XValueAxis()
        self.yValueAxis = YValueAxis()

        # this defines two series of 3 points.  Just an example.
        self.data = [
            ((1,1), (2,2), (2.5,1), (3,3), (4,5)),
            ((1,2), (2,3), (2.5,2), (3,4), (4,6))
            ]

        self.lines = TypedPropertyCollection(LinePlotProperties)
        self.lines.strokeWidth = 1
        self.lines[0].strokeColor = colors.red
        self.lines[1].strokeColor = colors.blue

        self.lineLabels = TypedPropertyCollection(Label)
        self.lineLabelFormat = None
        self.lineLabelArray = None

        # this says whether the origin is inside or outside
        # the bar - +10 means put the origin ten points
        # above the tip of the bar if value > 0, or ten
        # points inside if bar value < 0.  This is different
        # to label dx/dy which are not dependent on the
        # sign of the data.
        self.lineLabelNudge = 10
        # if you have multiple series, by default they butt
        # together.

        # New line chart attributes.
        self.joinedLines = 1 # Connect items with straight lines.

        #private attributes
        self._inFill = None
        self.annotations = []
        self.behindAxes = 0
        self.gridFirst = 0

    def demo(self):
        """Shows basic use of a line chart."""

        drawing = Drawing(400, 200)

        data = [
            ((1,1), (2,2), (2.5,1), (3,3), (4,5)),
            ((1,2), (2,3), (2.5,2), (3.5,5), (4,6))
            ]

        lp = LinePlot()

        lp.x = 50
        lp.y = 50
        lp.height = 125
        lp.width = 300
        lp.data = data
        lp.joinedLines = 1
        lp.lineLabelFormat = '%2.0f'
        lp.strokeColor = colors.black

        lp.lines[0].strokeColor = colors.red
        lp.lines[0].symbol = makeMarker('FilledCircle')
        lp.lines[1].strokeColor = colors.blue
        lp.lines[1].symbol = makeMarker('FilledDiamond')

        lp.xValueAxis.valueMin = 0
        lp.xValueAxis.valueMax = 5
        lp.xValueAxis.valueStep = 1

        lp.yValueAxis.valueMin = 0
        lp.yValueAxis.valueMax = 7
        lp.yValueAxis.valueStep = 1

        drawing.add(lp)

        return drawing


    def calcPositions(self):
        """Works out where they go.

        Sets an attribute _positions which is a list of
        lists of (x, y) matching the data.
        """

        self._seriesCount = len(self.data)
        self._rowLength = max(map(len,self.data))

        self._positions = []
        for rowNo in range(len(self.data)):
            line = []
            for colNo in range(len(self.data[rowNo])):
                datum = self.data[rowNo][colNo] # x,y value
                if type(datum[0]) == type(''):
                    x = self.xValueAxis.scale(mktime(mkTimeTuple(datum[0])))
                else:
                    x = self.xValueAxis.scale(datum[0])
                y = self.yValueAxis.scale(datum[1])
                line.append((x, y))
            self._positions.append(line)

    def _innerDrawLabel(self, rowNo, colNo, x, y):
        "Draw a label for a given item in the list."

        labelFmt = self.lineLabelFormat
        labelValue = self.data[rowNo][colNo][1] ###

        if labelFmt is None:
            labelText = None
        elif type(labelFmt) is StringType:
            if labelFmt == 'values':
                labelText = self.lineLabelArray[rowNo][colNo]
            else:
                labelText = labelFmt % labelValue
        elif hasattr(labelFmt,'__call__'):
            labelText = labelFmt(labelValue)
        else:
            raise ValueError("Unknown formatter type %s, expected string or function"%labelFmt)

        if labelText:
            label = self.lineLabels[(rowNo, colNo)]
            if not label.visible: return
            #hack to make sure labels are outside the bar
            if y > 0:
                label.setOrigin(x, y + self.lineLabelNudge)
            else:
                label.setOrigin(x, y - self.lineLabelNudge)
            label.setText(labelText)
        else:
            label = None
        return label

    def drawLabel(self, G, rowNo, colNo, x, y):
        '''Draw a label for a given item in the list.
        G must have an add method'''
        G.add(self._innerDrawLabel(rowNo,colNo,x,y))

    def makeLines(self):
        g = Group()
        bubblePlot = getattr(self,'_bubblePlot',None)
        if bubblePlot:
            yA = self.yValueAxis
            xA = self.xValueAxis
            bubbleR = min(yA._bubbleRadius,xA._bubbleRadius)
            bubbleMax = xA._bubbleMax

        labelFmt = self.lineLabelFormat

        P = range(len(self._positions))
        if self.reversePlotOrder: P.reverse()
        inFill = getattr(self,'_inFill',None)
        styleCount = len(self.lines)
        if inFill or [rowNo for rowNo in P if getattr(self.lines[rowNo%styleCount],'inFill',False)]:
            inFillY = self.xValueAxis._y
            inFillX0 = self.yValueAxis._x
            inFillX1 = inFillX0 + self.xValueAxis._length
            inFillG = getattr(self,'_inFillG',g)
        lG = getattr(self,'_lineG',g)
        # Iterate over data rows.
        for rowNo in P:
            row = self._positions[rowNo]
            rowStyle = self.lines[rowNo % styleCount]
            rowColor = getattr(rowStyle,'strokeColor',None)
            dash = getattr(rowStyle, 'strokeDashArray', None)

            if hasattr(rowStyle, 'strokeWidth'):
                width = rowStyle.strokeWidth
            elif hasattr(self.lines, 'strokeWidth'):
                width = self.lines.strokeWidth
            else:
                width = None

            # Iterate over data columns.
            if self.joinedLines:
                points = []
                for xy in row:
                    points = points + [xy[0], xy[1]]
                if inFill or getattr(rowStyle,'inFill',False):
                    fpoints = [inFillX0,inFillY] + points + [inFillX1,inFillY]
                    filler = getattr(rowStyle, 'filler', None)
                    if filler:
                        filler.fill(self,inFillG,rowNo,rowColor,fpoints)
                    else:
                        inFillG.add(Polygon(fpoints,fillColor=rowColor,strokeColor=rowColor,strokeWidth=width or 0.1))
                if inFill in (None,0,2):
                    line = PolyLine(points,strokeColor=rowColor,strokeLineCap=0,strokeLineJoin=1)
                    if width:
                        line.strokeWidth = width
                    if dash:
                        line.strokeDashArray = dash
                    lG.add(line)

            if hasattr(rowStyle, 'symbol'):
                uSymbol = rowStyle.symbol
            elif hasattr(self.lines, 'symbol'):
                uSymbol = self.lines.symbol
            else:
                uSymbol = None

            if uSymbol:
                j = -1
                if bubblePlot: drow = self.data[rowNo]
                for xy in row:
                    j += 1
                    symbol = uSymbol2Symbol(uSymbol,xy[0],xy[1],rowColor)
                    if symbol:
                        if bubblePlot:
                            symbol.size = bubbleR*(drow[j][2]/bubbleMax)**0.5
                        g.add(symbol)

            # Draw data labels.
            for colNo in range(len(row)):
                x1, y1 = row[colNo]
                self.drawLabel(g, rowNo, colNo, x1, y1)

            shader = getattr(rowStyle, 'shader', None)
            if shader: shader.shade(self,g,rowNo,rowColor,row)

        return g

    def draw(self):
        yA = self.yValueAxis
        xA = self.xValueAxis
        if getattr(self,'_bubblePlot',None):
            yA._bubblePlot = xA._bubblePlot = 1
        yA.setPosition(self.x, self.y, self.height)
        if yA: yA.joinAxis = xA
        if xA: xA.joinAxis = yA
        yA.configure(self.data)

        # if zero is in chart, put x axis there, otherwise use bottom.
        xAxisCrossesAt = yA.scale(0)
        if ((xAxisCrossesAt > self.y + self.height) or (xAxisCrossesAt < self.y)):
            y = self.y
        else:
            y = xAxisCrossesAt

        xA.setPosition(self.x, y, self.width)
        xA.configure(self.data)
        self.calcPositions()
        g = Group()
        g.add(self.makeBackground())
        if self._inFill or self.behindAxes:
            xA._joinToAxis()
            if self._inFill:
                self._inFillG = Group()
                g.add(self._inFillG)
            if self.behindAxes:
                self._lineG = Group()
                g.add(self._lineG)
        if self.gridFirst:
            xA.makeGrid(g,parent=self,dim=yA.getGridDims)
            yA.makeGrid(g,parent=self,dim=xA.getGridDims)
        g.add(xA)
        g.add(yA)
        if not self.gridFirst:
            xAdgl = getattr(xA,'drawGridLast',False)
            yAdgl = getattr(yA,'drawGridLast',False)
            if not xAdgl: xA.makeGrid(g,parent=self,dim=yA.getGridDims)
            if not yAdgl: yA.makeGrid(g,parent=self,dim=xA.getGridDims)
        annotations = getattr(self,'annotations',[])
        for a in annotations:
            if getattr(a,'beforeLines',None):
                g.add(a(self,xA.scale,yA.scale))
        g.add(self.makeLines())
        if not self.gridFirst:
            if xAdgl: xA.makeGrid(g,parent=self,dim=yA.getGridDims)
            if yAdgl: yA.makeGrid(g,parent=self,dim=xA.getGridDims)
        for a in annotations:
            if not getattr(a,'beforeLines',None):
                g.add(a(self,xA.scale,yA.scale))
        return g

    def addCrossHair(self,name,xv,yv,strokeColor=colors.black,strokeWidth=1,beforeLines=True):
        from reportlab.graphics.shapes import Group, Line
        annotations = [a for a in getattr(self,'annotations',[]) if getattr(a,'name',None)!=name]
        def annotation(self,xScale,yScale):
            x = xScale(xv)
            y = yScale(yv)
            g = Group()
            xA = xScale.im_self #the x axis
            g.add(Line(xA._x,y,xA._x+xA._length,y,strokeColor=strokeColor,strokeWidth=strokeWidth))
            yA = yScale.im_self #the y axis
            g.add(Line(x,yA._y,x,yA._y+yA._length,strokeColor=strokeColor,strokeWidth=strokeWidth))
            return g
        annotation.beforeLines = beforeLines
        annotations.append(annotation)
        self.annotations = annotations
示例#15
0
xAxis.valueSteps = [10, 15, 20, 30, 35, 40]
xAxis.configure(data)
xAxis.labels.boxAnchor = 'n'

drawing.add(xAxis)
""")


from reportlab.graphics import shapes
from reportlab.graphics.charts.axes import XValueAxis

drawing = Drawing(400, 100)

data = [(10, 20, 30, 40)]

xAxis = XValueAxis()
xAxis.setPosition(75, 50, 300)
xAxis.valueSteps = [10, 15, 20, 30, 35, 40]
xAxis.configure(data)
xAxis.labels.boxAnchor = 'n'

drawing.add(xAxis)

draw(drawing, 'An axis with non-equidistant tick marks')


disc("""
In addition to these properties, all axes classes have three
properties describing how to join two of them to each other.
Again, this is interesting only if you define your own charts
or want to modify the appearance of an existing chart using
示例#16
0
class LinePlot(AbstractLineChart):
    """Line plot with multiple lines.

    Both x- and y-axis are value axis (so there are no seperate
    X and Y versions of this class).
    """
    _attrMap = AttrMap(
        BASE=PlotArea,
        reversePlotOrder=AttrMapValue(isBoolean,
                                      desc='If true reverse plot order.',
                                      advancedUsage=1),
        lineLabelNudge=AttrMapValue(
            isNumber,
            desc='Distance between a data point and its label.',
            advancedUsage=1),
        lineLabels=AttrMapValue(
            None, desc='Handle to the list of data point labels.'),
        lineLabelFormat=AttrMapValue(
            None,
            desc='Formatting string or function used for data point labels.'),
        lineLabelArray=AttrMapValue(
            None,
            desc=
            'explicit array of line label values, must match size of data if present.'
        ),
        joinedLines=AttrMapValue(
            isNumber, desc='Display data points joined with lines if true.'),
        strokeColor=AttrMapValue(
            isColorOrNone,
            desc='Color used for background border of plot area.'),
        fillColor=AttrMapValue(
            isColorOrNone,
            desc='Color used for background interior of plot area.'),
        lines=AttrMapValue(None, desc='Handle of the lines.'),
        xValueAxis=AttrMapValue(None, desc='Handle of the x axis.'),
        yValueAxis=AttrMapValue(None, desc='Handle of the y axis.'),
        data=AttrMapValue(
            None, desc='Data to be plotted, list of (lists of) x/y tuples.'),
        annotations=AttrMapValue(
            None,
            desc='list of callables, will be called with self, xscale, yscale.',
            advancedUsage=1),
        behindAxes=AttrMapValue(isBoolean,
                                desc='If true use separate line group.',
                                advancedUsage=1),
        gridFirst=AttrMapValue(isBoolean,
                               desc='If true use draw grids before axes.',
                               advancedUsage=1),
    )

    def __init__(self):
        PlotArea.__init__(self)
        self.reversePlotOrder = 0

        self.xValueAxis = XValueAxis()
        self.yValueAxis = YValueAxis()

        # this defines two series of 3 points.  Just an example.
        self.data = [((1, 1), (2, 2), (2.5, 1), (3, 3), (4, 5)),
                     ((1, 2), (2, 3), (2.5, 2), (3, 4), (4, 6))]

        self.lines = TypedPropertyCollection(LinePlotProperties)
        self.lines.strokeWidth = 1
        self.lines[0].strokeColor = colors.red
        self.lines[1].strokeColor = colors.blue

        self.lineLabels = TypedPropertyCollection(Label)
        self.lineLabelFormat = None
        self.lineLabelArray = None

        # this says whether the origin is inside or outside
        # the bar - +10 means put the origin ten points
        # above the tip of the bar if value > 0, or ten
        # points inside if bar value < 0.  This is different
        # to label dx/dy which are not dependent on the
        # sign of the data.
        self.lineLabelNudge = 10
        # if you have multiple series, by default they butt
        # together.

        # New line chart attributes.
        self.joinedLines = 1  # Connect items with straight lines.

        #private attributes
        self._inFill = None
        self.annotations = []
        self.behindAxes = 0
        self.gridFirst = 0

    def demo(self):
        """Shows basic use of a line chart."""

        drawing = Drawing(400, 200)

        data = [((1, 1), (2, 2), (2.5, 1), (3, 3), (4, 5)),
                ((1, 2), (2, 3), (2.5, 2), (3.5, 5), (4, 6))]

        lp = LinePlot()

        lp.x = 50
        lp.y = 50
        lp.height = 125
        lp.width = 300
        lp.data = data
        lp.joinedLines = 1
        lp.lineLabelFormat = '%2.0f'
        lp.strokeColor = colors.black

        lp.lines[0].strokeColor = colors.red
        lp.lines[0].symbol = makeMarker('FilledCircle')
        lp.lines[1].strokeColor = colors.blue
        lp.lines[1].symbol = makeMarker('FilledDiamond')

        lp.xValueAxis.valueMin = 0
        lp.xValueAxis.valueMax = 5
        lp.xValueAxis.valueStep = 1

        lp.yValueAxis.valueMin = 0
        lp.yValueAxis.valueMax = 7
        lp.yValueAxis.valueStep = 1

        drawing.add(lp)

        return drawing

    def calcPositions(self):
        """Works out where they go.

        Sets an attribute _positions which is a list of
        lists of (x, y) matching the data.
        """

        self._seriesCount = len(self.data)
        self._rowLength = max(map(len, self.data))

        self._positions = []
        for rowNo in range(len(self.data)):
            line = []
            for colNo in range(len(self.data[rowNo])):
                datum = self.data[rowNo][colNo]  # x,y value
                if type(datum[0]) == type(''):
                    x = self.xValueAxis.scale(mktime(mkTimeTuple(datum[0])))
                else:
                    x = self.xValueAxis.scale(datum[0])
                y = self.yValueAxis.scale(datum[1])
                line.append((x, y))
            self._positions.append(line)

    def _innerDrawLabel(self, rowNo, colNo, x, y):
        "Draw a label for a given item in the list."

        labelFmt = self.lineLabelFormat
        labelValue = self.data[rowNo][colNo][1]  ###

        if labelFmt is None:
            labelText = None
        elif type(labelFmt) is StringType:
            if labelFmt == 'values':
                labelText = self.lineLabelArray[rowNo][colNo]
            else:
                labelText = labelFmt % labelValue
        elif hasattr(labelFmt, '__call__'):
            labelText = labelFmt(labelValue)
        else:
            raise ValueError(
                "Unknown formatter type %s, expected string or function" %
                labelFmt)

        if labelText:
            label = self.lineLabels[(rowNo, colNo)]
            if not label.visible: return
            #hack to make sure labels are outside the bar
            if y > 0:
                label.setOrigin(x, y + self.lineLabelNudge)
            else:
                label.setOrigin(x, y - self.lineLabelNudge)
            label.setText(labelText)
        else:
            label = None
        return label

    def drawLabel(self, G, rowNo, colNo, x, y):
        '''Draw a label for a given item in the list.
        G must have an add method'''
        G.add(self._innerDrawLabel(rowNo, colNo, x, y))

    def makeLines(self):
        g = Group()
        bubblePlot = getattr(self, '_bubblePlot', None)
        if bubblePlot:
            yA = self.yValueAxis
            xA = self.xValueAxis
            bubbleR = min(yA._bubbleRadius, xA._bubbleRadius)
            bubbleMax = xA._bubbleMax

        labelFmt = self.lineLabelFormat

        P = range(len(self._positions))
        if self.reversePlotOrder: P.reverse()
        inFill = getattr(self, '_inFill', None)
        styleCount = len(self.lines)
        if inFill or [
                rowNo for rowNo in P
                if getattr(self.lines[rowNo % styleCount], 'inFill', False)
        ]:
            inFillY = self.xValueAxis._y
            inFillX0 = self.yValueAxis._x
            inFillX1 = inFillX0 + self.xValueAxis._length
            inFillG = getattr(self, '_inFillG', g)
        lG = getattr(self, '_lineG', g)
        # Iterate over data rows.
        for rowNo in P:
            row = self._positions[rowNo]
            rowStyle = self.lines[rowNo % styleCount]
            rowColor = getattr(rowStyle, 'strokeColor', None)
            dash = getattr(rowStyle, 'strokeDashArray', None)

            if hasattr(rowStyle, 'strokeWidth'):
                width = rowStyle.strokeWidth
            elif hasattr(self.lines, 'strokeWidth'):
                width = self.lines.strokeWidth
            else:
                width = None

            # Iterate over data columns.
            if self.joinedLines:
                points = []
                for xy in row:
                    points += [xy[0], xy[1]]
                if inFill or getattr(rowStyle, 'inFill', False):
                    fpoints = [inFillX0, inFillY
                               ] + points + [inFillX1, inFillY]
                    filler = getattr(rowStyle, 'filler', None)
                    if filler:
                        filler.fill(self, inFillG, rowNo, rowColor, fpoints)
                    else:
                        inFillG.add(
                            Polygon(fpoints,
                                    fillColor=rowColor,
                                    strokeColor=rowColor,
                                    strokeWidth=width or 0.1))
                if inFill in (None, 0, 2):
                    line = PolyLine(points,
                                    strokeColor=rowColor,
                                    strokeLineCap=0,
                                    strokeLineJoin=1)
                    if width:
                        line.strokeWidth = width
                    if dash:
                        line.strokeDashArray = dash
                    lG.add(line)

            if hasattr(rowStyle, 'symbol'):
                uSymbol = rowStyle.symbol
            elif hasattr(self.lines, 'symbol'):
                uSymbol = self.lines.symbol
            else:
                uSymbol = None

            if uSymbol:
                j = -1
                if bubblePlot: drow = self.data[rowNo]
                for xy in row:
                    j += 1
                    symbol = uSymbol2Symbol(uSymbol, xy[0], xy[1], rowColor)
                    if symbol:
                        if bubblePlot:
                            symbol.size = bubbleR * (drow[j][2] /
                                                     bubbleMax)**0.5
                        g.add(symbol)

            # Draw data labels.
            for colNo in range(len(row)):
                x1, y1 = row[colNo]
                self.drawLabel(g, rowNo, colNo, x1, y1)

            shader = getattr(rowStyle, 'shader', None)
            if shader: shader.shade(self, g, rowNo, rowColor, row)

        return g

    def draw(self):
        yA = self.yValueAxis
        xA = self.xValueAxis
        if getattr(self, '_bubblePlot', None):
            yA._bubblePlot = xA._bubblePlot = 1
        yA.setPosition(self.x, self.y, self.height)
        if yA: yA.joinAxis = xA
        if xA: xA.joinAxis = yA
        yA.configure(self.data)

        # if zero is in chart, put x axis there, otherwise use bottom.
        xAxisCrossesAt = yA.scale(0)
        if ((xAxisCrossesAt > self.y + self.height)
                or (xAxisCrossesAt < self.y)):
            y = self.y
        else:
            y = xAxisCrossesAt

        xA.setPosition(self.x, y, self.width)
        xA.configure(self.data)
        self.calcPositions()
        g = Group()
        g.add(self.makeBackground())
        if self._inFill or self.behindAxes:
            xA._joinToAxis()
            if self._inFill:
                self._inFillG = Group()
                g.add(self._inFillG)
            if self.behindAxes:
                self._lineG = Group()
                g.add(self._lineG)
        if self.gridFirst:
            xA.makeGrid(g, parent=self, dim=yA.getGridDims)
            yA.makeGrid(g, parent=self, dim=xA.getGridDims)
        g.add(xA.draw())
        g.add(yA.draw())
        xAex = xA.visibleAxis and (xA._y, ) or ()
        yAex = yA.visibleAxis and (yA._x, ) or ()
        if not self.gridFirst:
            xAdgl = getattr(xA, 'drawGridLast', False)
            yAdgl = getattr(yA, 'drawGridLast', False)
            if not xAdgl:
                xA.makeGrid(g, parent=self, dim=yA.getGridDims, exclude=yAex)
            if not yAdgl:
                yA.makeGrid(g, parent=self, dim=xA.getGridDims, exclude=xAex)
        annotations = getattr(self, 'annotations', [])
        for a in annotations:
            if getattr(a, 'beforeLines', None):
                g.add(a(self, xA.scale, yA.scale))
        g.add(self.makeLines())
        if not self.gridFirst:
            if xAdgl:
                xA.makeGrid(g, parent=self, dim=yA.getGridDims, exclude=yAex)
            if yAdgl:
                yA.makeGrid(g, parent=self, dim=xA.getGridDims, exclude=xAex)
        for a in annotations:
            if not getattr(a, 'beforeLines', None):
                g.add(a(self, xA.scale, yA.scale))
        return g

    def addCrossHair(self,
                     name,
                     xv,
                     yv,
                     strokeColor=colors.black,
                     strokeWidth=1,
                     beforeLines=True):
        from reportlab.graphics.shapes import Group, Line
        annotations = [
            a for a in getattr(self, 'annotations', [])
            if getattr(a, 'name', None) != name
        ]

        def annotation(self, xScale, yScale):
            x = xScale(xv)
            y = yScale(yv)
            g = Group()
            xA = xScale.im_self  #the x axis
            g.add(
                Line(xA._x,
                     y,
                     xA._x + xA._length,
                     y,
                     strokeColor=strokeColor,
                     strokeWidth=strokeWidth))
            yA = yScale.im_self  #the y axis
            g.add(
                Line(x,
                     yA._y,
                     x,
                     yA._y + yA._length,
                     strokeColor=strokeColor,
                     strokeWidth=strokeWidth))
            return g

        annotation.beforeLines = beforeLines
        annotations.append(annotation)
        self.annotations = annotations
示例#17
0
    def drawLineChart(self, (names, start, end, data, title), reserved=None):
        w = PAGE_WIDTH - 2 * inch
        h = w * 0.6
        drawing = Drawing(w, h)

        lp = LinePlot()
        lp.x = 0
        lp.y = 0
        lp.height = h - 30
        lp.width = w
        lp.data = data
        lp.joinedLines = 1
        lp.strokeColor = colors.black

        lp.xValueAxis = XValueAxis()
        lp.xValueAxis.valueMin = start
        lp.xValueAxis.valueMax = end
        lp.xValueAxis.valueSteps = [(start + i * (end - start) / 5)
                                    for i in range(6)]
        lp.xValueAxis.labelTextFormat = lambda seconds: time.strftime(
            "%m/%d %H:%M", time.localtime(seconds))
        lp.xValueAxis.labels.angle = 35
        lp.xValueAxis.labels.fontName = 'Helvetica'
        lp.xValueAxis.labels.fontSize = 7
        lp.xValueAxis.labels.dy = -10
        lp.xValueAxis.labels.boxAnchor = 'e'
        lp.yValueAxis.labelTextFormat = lambda value: '%d MB' % (int(value) /
                                                                 1000)
        lp.yValueAxis.labels.fontName = 'Helvetica'
        lp.yValueAxis.labels.fontSize = 7
示例#18
0
    def __init__(self, desc=None):
        XValueAxis.__init__(self)

        self.desc = None
        if isString(desc) is True:
            self.desc = desc