Esempio n. 1
0
    def __init__(self, desc=None):
        XCategoryAxis.__init__(self)

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

        self.labels.fontName = DefaultFontName
Esempio n. 2
0
    def __init__(self):
        LineChart.__init__(self)

        # Allow for a bounding rectangle.
        self.strokeColor = None
        self.fillColor = None

        # Named so we have less recoding for the horizontal one :-)
        self.categoryAxis = XCategoryAxis()
        self.valueAxis = YValueAxis()

        # This defines two series of 3 points.  Just an example.
        self.data = [(100,110,120,130),
                     (70, 80, 80, 90)]
        self.categoryNames = ('North','South','East','West')

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

        # control spacing. if useAbsolute = 1 then
        # the next parameters are in points; otherwise
        # they are 'proportions' and are normalized to
        # fit the available space.
        self.useAbsolute = 0   #- not done yet
        self.groupSpacing = 1 #5

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

        # This says whether the origin is above or below
        # the data point. +10 means put the origin ten points
        # above the data point if value > 0, or ten
        # points below if data 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.
        self.inFill = 0
        self.reversePlotOrder = 0
Esempio n. 3
0
    def makeTickLabels(self):
        g = XCategoryAxis.makeTickLabels(self)

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

        return g
Esempio n. 4
0
    def test0(self):
        "Test two strings in drawing."

        path = outputfile("axestest0.ps")
        from reportlab.graphics.charts.axes import XCategoryAxis

        d = XCategoryAxis().demo()
        renderPS.drawToFile(d, path)
 def sample6d():
     "Sample drawing, xcat/yvalue axes, x connected at value 20 of y."
     drawing = Drawing(400, 200)
     data = [(10, 20, 30, 42)]
     yAxis = YValueAxis()
     yAxis.setPosition(50, 50, 125)
     yAxis.configure(data)
     xAxis = XCategoryAxis()
     xAxis._length = 300
     xAxis.configure(data)
     xAxis.joinAxis = yAxis
     xAxis.joinAxisMode = 'value'
     xAxis.joinAxisPos = 20
     xAxis.categoryNames = ['Beer', 'Wine', 'Meat', 'Cannelloni']
     xAxis.labels.boxAnchor = 'n'
     drawing.add(xAxis)
     drawing.add(yAxis)
     return drawing
        def sample0b():
            "Sample drawing with one xcat axis and one bucket only."

            drawing = Drawing(400, 200)

            data = [(10, )]

            xAxis = XCategoryAxis()
            xAxis.setPosition(75, 75, 300)
            xAxis.configure(data)
            xAxis.categoryNames = ['Ying']
            xAxis.labels.boxAnchor = 'n'
            drawing.add(xAxis)
            return drawing
Esempio n. 7
0
 def sample6d():
     "Sample drawing, xcat/yvalue axes, x connected at value 20 of y."
     drawing = Drawing(400, 200)
     data = [(10, 20, 30, 42)]
     yAxis = YValueAxis()
     yAxis.setPosition(50, 50, 125)
     yAxis.configure(data)
     xAxis = XCategoryAxis()
     xAxis._length = 300
     xAxis.configure(data)
     xAxis.joinAxis = yAxis
     xAxis.joinAxisMode = 'value'
     xAxis.joinAxisPos = 20
     xAxis.categoryNames = ['Beer', 'Wine', 'Meat', 'Cannelloni']
     xAxis.labels.boxAnchor = 'n'
     drawing.add(xAxis)
     drawing.add(yAxis)
     return drawing
Esempio n. 8
0
    def __init__(self):
        LineChart.__init__(self)

        # Allow for a bounding rectangle.
        self.strokeColor = None
        self.fillColor = None

        # Named so we have less recoding for the horizontal one :-)
        self.categoryAxis = XCategoryAxis()
        self.valueAxis = YValueAxis()

        # This defines two series of 3 points.  Just an example.
        self.data = [(100,110,120,130),
                     (70, 80, 80, 90)]
        self.categoryNames = ('North','South','East','West')

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

        # control spacing. if useAbsolute = 1 then
        # the next parameters are in points; otherwise
        # they are 'proportions' and are normalized to
        # fit the available space.
        self.useAbsolute = 0   #- not done yet
        self.groupSpacing = 1 #5

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

        # This says whether the origin is above or below
        # the data point. +10 means put the origin ten points
        # above the data point if value > 0, or ten
        # points below if data 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.
        self.inFill = 0
        self.reversePlotOrder = 0
Esempio n. 9
0
        def sample0b():
            "Sample drawing with one xcat axis and one bucket only."

            drawing = Drawing(400, 200)

            data = [(10,)]

            xAxis = XCategoryAxis()
            xAxis.setPosition(75, 75, 300)
            xAxis.configure(data)
            xAxis.categoryNames = ['Ying']
            xAxis.labels.boxAnchor = 'n'
            drawing.add(xAxis)
            return drawing
 def sample1():
     "Sample drawing containing two unconnected axes."
     from reportlab.graphics.shapes import _baseGFontNameB
     drawing = Drawing(400, 200)
     data = [(10, 20, 30, 42)]
     xAxis = XCategoryAxis()
     xAxis.setPosition(75, 75, 300)
     xAxis.configure(data)
     xAxis.categoryNames = ['Beer', 'Wine', 'Meat', 'Cannelloni']
     xAxis.labels.boxAnchor = 'n'
     xAxis.labels[3].dy = -15
     xAxis.labels[3].angle = 30
     xAxis.labels[3].fontName = _baseGFontNameB
     yAxis = YValueAxis()
     yAxis.setPosition(50, 50, 125)
     yAxis.configure(data)
     drawing.add(xAxis)
     drawing.add(yAxis)
     return drawing
Esempio n. 11
0
        def sample0c():
            "Sample drawing with one xcat axis and two buckets."

            class DDFStyle(ParagraphStyle):
                def __init__(self, **kwds):
                    if 'fillColor' in kwds:
                        kwds['textColor'] = kwds.pop('fillColor')
                    kwds.update({
                        k: v
                        for k, v in (
                            ('name', 'DDFStyle'),
                            ('alignment', 0),
                            ('hyphenationLang', None),
                            ('hyphenationMinWordLength', 4),
                            ('uriWasteReduce', 0.3),
                            ('embeddedHyphenation', 2),
                            ('textColor', colors.blue),
                            ('backColor', colors.yellow),
                        ) if k not in kwds
                    })
                    super().__init__(**kwds)

            drawing = Drawing(400, 200)
            data = [(10, 20)]
            xAxis = XCategoryAxis()
            xAxis.labels.ddfKlass = Paragraph
            xAxis.labels.ddfStyle = DDFStyle
            xAxis.labels.maxWidth = 48
            xAxis.labels.fillColor = colors.red
            xAxis.labels.fontName = 'Helvetica'
            xAxis.labels.fontSize = 12
            xAxis.labels.leading = 12
            xAxis.setPosition(75, 75, 100)
            xAxis.configure(data)
            xAxis.categoryNames = [
                'Ying and Mao\xadTse\xadTung are bonkers',
                'Yang is not a comm\xadun\xadist'
            ]
            xAxis.labels.boxAnchor = 'n'
            drawing.add(xAxis)
            return drawing
Esempio n. 12
0
def axes_demo():
    drawing = shapes.Drawing(width=500, height=300)

    data = [(5, 10, 15, 20), (10, 17, 25, 31)]

    x_axis = XCategoryAxis()
    x_axis.setPosition(100, 100, 350)
    x_axis.configure(data, barWidth=None)
    x_axis.categoryNames = ['Python', 'Ruby', 'C++', 'Haskell', 'Java']
    x_axis.labels.boxAnchor = 'n'
    x_axis.labels[0].angle = 45
    x_axis.labels[0].fontName = 'Times-Bold'
    x_axis.labels[1].fontName = 'Courier'
    x_axis.labels[1].fontSize = 16
    drawing.add(x_axis)

    y_axis = YValueAxis()
    y_axis.setPosition(75, 75, 150)
    y_axis.configure(data)
    drawing.add(y_axis)

    renderPDF.drawToFile(drawing, 'axes_demo.pdf')
Esempio n. 13
0
 def sample1():
     "Sample drawing containing two unconnected axes."
     from reportlab.graphics.shapes import _baseGFontNameB
     drawing = Drawing(400, 200)
     data = [(10, 20, 30, 42)]
     xAxis = XCategoryAxis()
     xAxis.setPosition(75, 75, 300)
     xAxis.configure(data)
     xAxis.categoryNames = ['Beer','Wine','Meat','Cannelloni']
     xAxis.labels.boxAnchor = 'n'
     xAxis.labels[3].dy = -15
     xAxis.labels[3].angle = 30
     xAxis.labels[3].fontName = _baseGFontNameB
     yAxis = YValueAxis()
     yAxis.setPosition(50, 50, 125)
     yAxis.configure(data)
     drawing.add(xAxis)
     drawing.add(yAxis)
     return drawing
Esempio n. 14
0
""")

disc("""
This drawing shows two axes, one of each kind, which have been created
directly without reference to any chart:
""")


from reportlab.graphics import shapes
from reportlab.graphics.charts.axes import XCategoryAxis,YValueAxis

drawing = Drawing(400, 200)

data = [(10, 20, 30, 40), (15, 22, 37, 42)]

xAxis = XCategoryAxis()
xAxis.setPosition(75, 75, 300)
xAxis.configure(data)
xAxis.categoryNames = ['Beer', 'Wine', 'Meat', 'Cannelloni']
xAxis.labels.boxAnchor = 'n'
xAxis.labels[3].dy = -15
xAxis.labels[3].angle = 30
xAxis.labels[3].fontName = 'Times-Bold'

yAxis = YValueAxis()
yAxis.setPosition(50, 50, 125)
yAxis.configure(data)

drawing.add(xAxis)
drawing.add(yAxis)
Esempio n. 15
0
    def generateGraphs(self, x, y):
        (x1, y1, Width, Height) = self._getGraphRegion(x, y)
        #Draw Axes
        yVAxis = YValueAxis()
        #If we got numeric X vals, we use a ValueAxis, otherwise CategoryAxis.
        if len(self.x_vals) > 0:
            if isinstance(self.x_vals[0], str):
                xVAxis = XCategoryAxis()
            else:
                xVAxis = XValueAxis()
        else:
            return -1
        
        (y_min, y_max, y_step) = self.getValueAxisScale(yVAxis, [self.y_vals])

        if y_min == -1 and y_min == -1 and y_step == -1:
            return -1
        
        (self.valueMin, self.valueMax, self.valueStep) = (y_min, y_max, y_step)
        
        (SizeXaxis, SizeYaxis) = self.getSizes()
        #lot of ugliness in here to get the split chart working :|
        if self.betweenSplitsF == True:
            if self.numSplits == 0:
                self.tmpYVal = SizeYaxis
            else:
                SizeYaxis = self.tmpYVal
        if self.numSplits > 0:
            xVAxis.visibleLabels = False
            xVAxis.visibleTicks = False
        X_start_pos = x1 - x + SizeYaxis
        X_width = Width - SizeYaxis - 10
        if self.betweenSplitsF == True:
            if self.numSplits > 0:
                Y_start_pos = y1 - y + SizeXaxis + (self.numSplits *
                        self.height) - (self.numSplits * 15)
            else:
                Y_start_pos = y1 - y + SizeXaxis + (self.numSplits *
                        self.height)
            Y_height = Height - SizeXaxis + 40
        else:
            Y_start_pos = y1 - y + SizeXaxis + (self.numSplits *
                    self.height)
            Y_height = Height - SizeXaxis
        xVAxis.setPosition(X_start_pos, Y_start_pos, X_width)
        if isinstance(xVAxis, XValueAxis):
            dataList = []
            dataTuple =  reduce(lambda a,b: a + (b,), self.x_vals, ())
            dataList.append(dataTuple)
            xVAxis.configure(dataList)
            xVAxis.labelTextFormat = '%0.' + '%d' % self.xAxisDigits + 'f'
        else:
            dataList = []
            zerodata = [0 for val in self.x_vals]
            dataTuple =  reduce(lambda a,b: a + (b,), zerodata, ())
            dataList.append(dataTuple)
            xVAxis.configure(dataList)
            xVAxis.categoryNames = self.x_vals
            #Ugly hack for setting the labels.dy. Empirical: If there are more than 5 
            #chars, dy = -35 fits fine (assuming the angle would be > 75,when we have 
            #so long val)
            maxLen = 0
            for val in self.x_vals:
                valLen = len(val)
                if valLen > maxLen:
                    maxLen = valLen
            if maxLen > 5:
                xVAxis.labels.dy = -35
                           
        xVAxis.labels.fontName = 'Helvetica'
        xVAxis.labels.fontSize = 7
        xVAxis.labels.angle = self.xValsDisplayAngle
        drawLegendF = False
        if len(self.legendList) > 0:
            drawLegendF = True
        drawLabelF = False
        lblCounts = len(self.x_vals) * len(self.y_vals)
        if lblCounts <= 30 and self.displayDataLbls == True:
            drawLabelF = True
        if len(self.x_vals) == 1:
            drawLabelF = True            
        #hack to increase chart height to include legend and labels
        total_height = 0
        legendHeight = 0
        if drawLegendF == True:
            #Kludge: We enchroach the space needed for legends by bringing down the 
            #y value by 28 (in drawOn()), we use that space here
            legendHeight = Y_height + 28
        graph_height = Y_height
        yVAxis.setPosition(X_start_pos, Y_start_pos, Y_height)
        yVAxis.valueMin = y_min
        yVAxis.valueMax = y_max    
        yVAxis.valueStep = y_step
        yVAxis.labels.fontName = 'Helvetica'
        yVAxis.labels.fontSize = 7
        yVAxis.labelTextFormat = '%0.' + '%d' % self.yAxisDigits + 'f'
        yVAxis.configure(self.y_vals)
        #will later sync the yVAxis as the ValueAxis of the graph
        self.drawing.add(xVAxis)
        if self.numSplits == 0:
            tmp = self.height
            self.height = self.origHeight
            self._drawLabels(self.title, self.x_label, self.y_label)
            self.height = tmp
        for graphtype in self.graphList:
            #Draw only one set of Legends/Labels for any dataset,
            #even if there are multiple charts drawn for the same dataset
            if self.labelsDrawnF == True and self.numSplits == 0:
                drawLabelF = False
            if self.legendsDrawnF == True and self.numSplits == 0:
                drawLegendF = False
            if graphtype == 'Bar':
                GraphObj = VerticalBarChart()
                GraphObj.valueAxis = yVAxis
                self.drawGraph(GraphObj, X_start_pos, Y_start_pos, X_width,
                        graph_height, drawLabelF, drawLegendF, legendHeight)
            if graphtype == 'Line':
                GraphObj = HorizontalLineChart()
                GraphObj.valueAxis = yVAxis
                self.drawGraph(GraphObj, X_start_pos, Y_start_pos, X_width,
                        graph_height, drawLabelF, drawLegendF, legendHeight)
Esempio n. 16
0
class HorizontalLineChart(LineChart):
    """Line chart with multiple lines.

    A line chart is assumed to have one category and one value axis.
    Despite its generic name this particular line chart class has
    a vertical value axis and a horizontal category one. It may
    evolve into individual horizontal and vertical variants (like
    with the existing bar charts).

    Available attributes are:

        x: x-position of lower-left chart origin
        y: y-position of lower-left chart origin
        width: chart width
        height: chart height

        useAbsolute: disables auto-scaling of chart elements (?)
        lineLabelNudge: distance of data labels to data points
        lineLabels: labels associated with data values
        lineLabelFormat: format string or callback function
        groupSpacing: space between categories

        joinedLines: enables drawing of lines

        strokeColor: color of chart lines (?)
        fillColor: color for chart background (?)
        lines: style list, used cyclically for data series

        valueAxis: value axis object
        categoryAxis: category axis object
        categoryNames: category names

        data: chart data, a list of data series of equal length
    """

    _attrMap = AttrMap(BASE=LineChart,
        useAbsolute = AttrMapValue(isNumber, desc='Flag to use absolute spacing values.',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.'),
        groupSpacing = AttrMapValue(isNumber, desc='? - Likely to disappear.'),
        joinedLines = AttrMapValue(isNumber, desc='Display data points joined with lines if true.'),
        lines = AttrMapValue(None, desc='Handle of the lines.'),
        valueAxis = AttrMapValue(None, desc='Handle of the value axis.'),
        categoryAxis = AttrMapValue(None, desc='Handle of the category axis.'),
        categoryNames = AttrMapValue(isListOfStringsOrNone, desc='List of category names.'),
        data = AttrMapValue(None, desc='Data to be plotted, list of (lists of) numbers.'),
        inFill = AttrMapValue(isBoolean, desc='Whether infilling should be done.',advancedUsage=1),
        reversePlotOrder = AttrMapValue(isBoolean, desc='If true reverse plot order.',advancedUsage=1),
        annotations = AttrMapValue(None, desc='list of callables, will be called with self, xscale, yscale.',advancedUsage=1),
        )

    def __init__(self):
        LineChart.__init__(self)

        # Allow for a bounding rectangle.
        self.strokeColor = None
        self.fillColor = None

        # Named so we have less recoding for the horizontal one :-)
        self.categoryAxis = XCategoryAxis()
        self.valueAxis = YValueAxis()

        # This defines two series of 3 points.  Just an example.
        self.data = [(100,110,120,130),
                     (70, 80, 80, 90)]
        self.categoryNames = ('North','South','East','West')

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

        # control spacing. if useAbsolute = 1 then
        # the next parameters are in points; otherwise
        # they are 'proportions' and are normalized to
        # fit the available space.
        self.useAbsolute = 0   #- not done yet
        self.groupSpacing = 1 #5

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

        # This says whether the origin is above or below
        # the data point. +10 means put the origin ten points
        # above the data point if value > 0, or ten
        # points below if data 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.
        self.inFill = 0
        self.reversePlotOrder = 0


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

        drawing = Drawing(200, 100)

        data = [
                (13, 5, 20, 22, 37, 45, 19, 4),
                (14, 10, 21, 28, 38, 46, 25, 5)
                ]

        lc = HorizontalLineChart()

        lc.x = 20
        lc.y = 10
        lc.height = 85
        lc.width = 170
        lc.data = data
        lc.lines.symbol = makeMarker('Circle')

        drawing.add(lc)

        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(list(map(len,self.data)))

        if self.useAbsolute:
            # Dimensions are absolute.
            normFactor = 1.0
        else:
            # Dimensions are normalized to fit.
            normWidth = self.groupSpacing
            availWidth = self.categoryAxis.scale(0)[1]
            normFactor = availWidth / normWidth

        self._positions = []
        for rowNo in range(len(self.data)):
            lineRow = []
            for colNo in range(len(self.data[rowNo])):
                datum = self.data[rowNo][colNo]
                if datum is not None:
                    (groupX, groupWidth) = self.categoryAxis.scale(colNo)
                    x = groupX + (0.5 * self.groupSpacing * normFactor)
                    y = self.valueAxis.scale(0)
                    height = self.valueAxis.scale(datum) - y
                    lineRow.append((x, y+height))
            self._positions.append(lineRow)


    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]

        if labelFmt is None:
            labelText = None
        elif type(labelFmt) is str:
            if labelFmt == 'values':
                try:
                    labelText = self.lineLabelArray[rowNo][colNo]
                except:
                    labelText = None
            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
            # Make sure labels are some distance off the data point.
            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()

        labelFmt = self.lineLabelFormat
        P = list(range(len(self._positions)))
        if self.reversePlotOrder: P.reverse()
        inFill = self.inFill
        if inFill:
            inFillY = self.categoryAxis._y
            inFillX0 = self.valueAxis._x
            inFillX1 = inFillX0 + self.categoryAxis._length
            inFillG = getattr(self,'_inFillG',g)

        # Iterate over data rows.
        for rowNo in P:
            row = self._positions[rowNo]
            styleCount = len(self.lines)
            styleIdx = rowNo % styleCount
            rowStyle = self.lines[styleIdx]
            rowColor = rowStyle.strokeColor
            dash = getattr(rowStyle, 'strokeDashArray', None)

            if hasattr(self.lines[styleIdx], 'strokeWidth'):
                strokeWidth = self.lines[styleIdx].strokeWidth
            elif hasattr(self.lines, 'strokeWidth'):
                strokeWidth = self.lines.strokeWidth
            else:
                strokeWidth = None

            # Iterate over data columns.
            if self.joinedLines:
                points = []
                for colNo in range(len(row)):
                    points += row[colNo]
                if inFill:
                    points = points + [inFillX1,inFillY,inFillX0,inFillY]
                    inFillG.add(Polygon(points,fillColor=rowColor,strokeColor=rowColor,strokeWidth=0.1))
                else:
                    line = PolyLine(points,strokeColor=rowColor,strokeLineCap=0,strokeLineJoin=1)
                    if strokeWidth:
                        line.strokeWidth = strokeWidth
                    if dash:
                        line.strokeDashArray = dash
                    g.add(line)

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

            if uSymbol:
                for colNo in range(len(row)):
                    x1, y1 = row[colNo]
                    symbol = uSymbol2Symbol(uSymbol,x1,y1,rowStyle.strokeColor)
                    if symbol: g.add(symbol)

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

        return g

    def draw(self):
        "Draws itself."

        vA, cA = self.valueAxis, self.categoryAxis
        vA.setPosition(self.x, self.y, self.height)
        if vA: vA.joinAxis = cA
        if cA: cA.joinAxis = vA
        vA.configure(self.data)

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

        cA.setPosition(self.x, y, self.width)
        cA.configure(self.data)

        self.calcPositions()

        g = Group()
        g.add(self.makeBackground())
        if self.inFill:
            self._inFillG = Group()
            g.add(self._inFillG)

        g.add(cA)
        g.add(vA)
        cAdgl = getattr(cA,'drawGridLast',False)
        vAdgl = getattr(vA,'drawGridLast',False)
        if not cAdgl: cA.makeGrid(g,parent=self,dim=vA.getGridDims)
        if not vAdgl: vA.makeGrid(g,parent=self,dim=cA.getGridDims)
        g.add(self.makeLines())
        if cAdgl: cA.makeGrid(g,parent=self,dim=vA.getGridDims)
        if vAdgl: vA.makeGrid(g,parent=self,dim=cA.getGridDims)
        for a in getattr(self,'annotations',()): g.add(a(self,cA.scale,vA.scale))
        return g
Esempio n. 17
0
def generatePdfReport(request):
    # Create the HttpResponse object with the appropriate PDF headers.
    response = HttpResponse(content_type='application/pdf')
    response['Content-Disposition'] = 'attachment; filename="somefilename.pdf"'

    # Create the PDF object, using the response object as its "file."
    p = canvas.Canvas(response)
    
    # Draw things on the PDF. Here's where the PDF generation happens.
    # See the ReportLab documentation for the full list of functionality.
    Title="Test Report"
    PAGE_HEIGHT=defaultPageSize[1]  
    PAGE_WIDTH=defaultPageSize[0]  
    p.drawCentredString(PAGE_WIDTH/2.0, PAGE_HEIGHT-108, Title)
    p.drawString(100,900,"Test Configuration")
    configuration=request.session["test_configuration"]
    data=[['Operation','On/Off','Percentage','Keys','Size']]
    if 'readState' in configuration:
        readData=[['Read',configuration['readState'],configuration['readPercentage'],configuration['readKeys'],configuration['readSize']]]
    else:
        readData=[['Read','0','0','0','0']]
    data=data+readData
    if 'writeState' in configuration:
        writeData=[['Write',configuration['writeState'],configuration['writePercentage'],configuration['writeKeys'],configuration['writeSize']]]
    else:
        writeData=[['Write','0','0','0','0']]
    data=data+writeData
    if 'updateState' in configuration:
        updateData=[['Update',configuration['updateState'],configuration['updatePercentage'],configuration['updateKeys'],configuration['updateSize']]]
    else:
        updateData=[['Update','0','0','0','0']]
    data=data+updateData
    table = Table(data, colWidths=100, rowHeights=20)
    table.hAlign="CENTER"
    table.setStyle(TableStyle())
    table.wrapOn(p, 300, 800)
    table.drawOn(p,80,550)
    
    p.drawString(80,700,"Test Configuration")
    p.drawString(80,500,"Test Time : ")
    p.drawString(200,500,str(t1.getTime()) + " miliseconds " )
    p.drawString(80,400,"Test Chart")
    p.saveState()
    
    drawing = Drawing(10, 10)
    data = [(10, 20, 30, 40), (15, 22, 37, 42)]
    xAxis = XCategoryAxis()
    xAxis.setPosition(75, 75, 300)
    xAxis.configure(data)
    xAxis.categoryNames = ['Beer', 'Wine', 'Meat', 'Cannelloni']
    xAxis.labels.boxAnchor = 'n'
    xAxis.labels[3].dy = -15
    xAxis.labels[3].angle = 30
    xAxis.labels[3].fontName = 'Times-Bold'
    yAxis = YValueAxis()
    yAxis.setPosition(50, 50, 125)
    yAxis.configure(data)
    drawing.add(xAxis)
    drawing.add(yAxis)
    
    # Close the PDF object cleanly, and we're done.
    p.showPage()
    p.save()
    return response
Esempio n. 18
0
class HorizontalLineChart(LineChart):
    """Line chart with multiple lines.

    A line chart is assumed to have one category and one value axis.
    Despite its generic name this particular line chart class has
    a vertical value axis and a horizontal category one. It may
    evolve into individual horizontal and vertical variants (like
    with the existing bar charts).

    Available attributes are:

        x: x-position of lower-left chart origin
        y: y-position of lower-left chart origin
        width: chart width
        height: chart height

        useAbsolute: disables auto-scaling of chart elements (?)
        lineLabelNudge: distance of data labels to data points
        lineLabels: labels associated with data values
        lineLabelFormat: format string or callback function
        groupSpacing: space between categories

        joinedLines: enables drawing of lines

        strokeColor: color of chart lines (?)
        fillColor: color for chart background (?)
        lines: style list, used cyclically for data series

        valueAxis: value axis object
        categoryAxis: category axis object
        categoryNames: category names

        data: chart data, a list of data series of equal length
    """

    _attrMap = AttrMap(BASE=LineChart,
        useAbsolute = AttrMapValue(isNumber, desc='Flag to use absolute spacing values.',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.'),
        groupSpacing = AttrMapValue(isNumber, desc='? - Likely to disappear.'),
        joinedLines = AttrMapValue(isNumber, desc='Display data points joined with lines if true.'),
        lines = AttrMapValue(None, desc='Handle of the lines.'),
        valueAxis = AttrMapValue(None, desc='Handle of the value axis.'),
        categoryAxis = AttrMapValue(None, desc='Handle of the category axis.'),
        categoryNames = AttrMapValue(isListOfStringsOrNone, desc='List of category names.'),
        data = AttrMapValue(None, desc='Data to be plotted, list of (lists of) numbers.'),
        inFill = AttrMapValue(isBoolean, desc='Whether infilling should be done.',advancedUsage=1),
        reversePlotOrder = AttrMapValue(isBoolean, desc='If true reverse plot order.',advancedUsage=1),
        annotations = AttrMapValue(None, desc='list of callables, will be called with self, xscale, yscale.',advancedUsage=1),
        )

    def __init__(self):
        LineChart.__init__(self)

        # Allow for a bounding rectangle.
        self.strokeColor = None
        self.fillColor = None

        # Named so we have less recoding for the horizontal one :-)
        self.categoryAxis = XCategoryAxis()
        self.valueAxis = YValueAxis()

        # This defines two series of 3 points.  Just an example.
        self.data = [(100,110,120,130),
                     (70, 80, 80, 90)]
        self.categoryNames = ('North','South','East','West')

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

        # control spacing. if useAbsolute = 1 then
        # the next parameters are in points; otherwise
        # they are 'proportions' and are normalized to
        # fit the available space.
        self.useAbsolute = 0   #- not done yet
        self.groupSpacing = 1 #5

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

        # This says whether the origin is above or below
        # the data point. +10 means put the origin ten points
        # above the data point if value > 0, or ten
        # points below if data 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.
        self.inFill = 0
        self.reversePlotOrder = 0


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

        drawing = Drawing(200, 100)

        data = [
                (13, 5, 20, 22, 37, 45, 19, 4),
                (14, 10, 21, 28, 38, 46, 25, 5)
                ]

        lc = HorizontalLineChart()

        lc.x = 20
        lc.y = 10
        lc.height = 85
        lc.width = 170
        lc.data = data
        lc.lines.symbol = makeMarker('Circle')

        drawing.add(lc)

        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(list(map(len,self.data)))

        if self.useAbsolute:
            # Dimensions are absolute.
            normFactor = 1.0
        else:
            # Dimensions are normalized to fit.
            normWidth = self.groupSpacing
            availWidth = self.categoryAxis.scale(0)[1]
            normFactor = availWidth / normWidth
        self._normFactor = normFactor
        self._yzero = yzero = self.valueAxis.scale(0)
        self._hngs = hngs = 0.5 * self.groupSpacing * normFactor

        self._positions = []
        for rowNo in range(len(self.data)):
            lineRow = []
            for colNo in range(len(self.data[rowNo])):
                datum = self.data[rowNo][colNo]
                if datum is not None:
                    (groupX, groupWidth) = self.categoryAxis.scale(colNo)
                    x = groupX + hngs
                    y = yzero
                    height = self.valueAxis.scale(datum) - y
                    lineRow.append((x, y+height))
            self._positions.append(lineRow)


    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]

        if labelFmt is None:
            labelText = None
        elif type(labelFmt) is str:
            if labelFmt == 'values':
                try:
                    labelText = self.lineLabelArray[rowNo][colNo]
                except:
                    labelText = None
            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
            # Make sure labels are some distance off the data point.
            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()

        labelFmt = self.lineLabelFormat
        P = list(range(len(self._positions)))
        if self.reversePlotOrder: P.reverse()
        inFill = self.inFill
        if inFill:
            inFillY = self.categoryAxis._y
            inFillX0 = self.valueAxis._x
            inFillX1 = inFillX0 + self.categoryAxis._length
            inFillG = getattr(self,'_inFillG',g)
        yzero = self._yzero

        # Iterate over data rows.
        for rowNo in P:
            row = self._positions[rowNo]
            styleCount = len(self.lines)
            styleIdx = rowNo % styleCount
            rowStyle = self.lines[styleIdx]
            rowColor = rowStyle.strokeColor
            dash = getattr(rowStyle, 'strokeDashArray', None)
            lineStyle = getattr(rowStyle,'lineStyle',None)

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

            # Iterate over data columns.
            if lineStyle=='bar':
                barWidth = getattr(rowStyle,'barWidth',Percentage(50))
                fillColor = getattr(rowStyle,'fillColor',rowColor)
                if isinstance(barWidth,Percentage):
                    hbw = self._hngs*barWidth*0.01
                else:
                    hbw = barWidth*0.5
                for colNo in range(len(row)):
                    x,y = row[colNo]
                    g.add(Rect(x-hbw,min(y,yzero),2*hbw,abs(y-yzero),strokeWidth=strokeWidth,strokeColor=rowColor,fillColor=fillColor))
            elif self.joinedLines or lineStyle=='joinedLine':
                points = []
                for colNo in range(len(row)):
                    points += row[colNo]
                if inFill:
                    points = points + [inFillX1,inFillY,inFillX0,inFillY]
                    inFillG.add(Polygon(points,fillColor=rowColor,strokeColor=rowColor,strokeWidth=0.1))
                else:
                    line = PolyLine(points,strokeColor=rowColor,strokeLineCap=0,strokeLineJoin=1)
                    if strokeWidth:
                        line.strokeWidth = strokeWidth
                    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:
                for colNo in range(len(row)):
                    x1, y1 = row[colNo]
                    symbol = uSymbol2Symbol(uSymbol,x1,y1,rowStyle.strokeColor)
                    if symbol: g.add(symbol)

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

        return g

    def draw(self):
        "Draws itself."

        vA, cA = self.valueAxis, self.categoryAxis
        vA.setPosition(self.x, self.y, self.height)
        if vA: vA.joinAxis = cA
        if cA: cA.joinAxis = vA
        vA.configure(self.data)

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

        cA.setPosition(self.x, y, self.width)
        cA.configure(self.data)

        self.calcPositions()

        g = Group()
        g.add(self.makeBackground())
        if self.inFill:
            self._inFillG = Group()
            g.add(self._inFillG)

        g.add(cA)
        g.add(vA)
        cAdgl = getattr(cA,'drawGridLast',False)
        vAdgl = getattr(vA,'drawGridLast',False)
        if not cAdgl: cA.makeGrid(g,parent=self,dim=vA.getGridDims)
        if not vAdgl: vA.makeGrid(g,parent=self,dim=cA.getGridDims)
        g.add(self.makeLines())
        if cAdgl: cA.makeGrid(g,parent=self,dim=vA.getGridDims)
        if vAdgl: vA.makeGrid(g,parent=self,dim=cA.getGridDims)
        for a in getattr(self,'annotations',()): g.add(a(self,cA.scale,vA.scale))
        return g
Esempio n. 19
0
disc(
    """
This drawing shows two axes, one of each kind, which have been created
directly without reference to any chart:
"""
)


from reportlab.graphics import shapes
from reportlab.graphics.charts.axes import XCategoryAxis, YValueAxis

drawing = Drawing(400, 200)

data = [(10, 20, 30, 40), (15, 22, 37, 42)]

xAxis = XCategoryAxis()
xAxis.setPosition(75, 75, 300)
xAxis.configure(data)
xAxis.categoryNames = ["Beer", "Wine", "Meat", "Cannelloni"]
xAxis.labels.boxAnchor = "n"
xAxis.labels[3].dy = -15
xAxis.labels[3].angle = 30
xAxis.labels[3].fontName = "Times-Bold"

yAxis = YValueAxis()
yAxis.setPosition(50, 50, 125)
yAxis.configure(data)

drawing.add(xAxis)
drawing.add(yAxis)