Reportlab生成PDF文件

  • 数据柱旁边的标签是垂直的:chart.barLabels.angle=90

  • 类别轴属性labelAxisMode(categoryAxis.labelAxisMode)设置类别坐标轴的标签位置    

  • 用annotation属性画了一条直线

代码和注释:

"Vertical labels"
from reportlab.lib.colors import PCMYKColor, black, red
from reportlab.graphics.charts.legends import Legend
from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin, String, Line
from reportlab.lib.validators import Auto
from reportlab.lib.formatters import DecimalFormatter
from reportlab.graphics.charts.barcharts import VerticalBarChart

class BarChart_VLabelsAnnotation(_DrawingEditorMixin,Drawing):
    def __init__(self,width=348,height=146,*args,**kw):
        Drawing.__init__(self,width,height,*args,**kw)
        fontName = 'Helvetica'

        # 添加垂直的直方图
        self._add(self,VerticalBarChart(),name='chart',validate=None,desc=None)

        # 直方图设置
        self.chart.width = self.width - self.chart.x
        self.chart.height = self.height - self.chart.y - 20
        self.chart.groupSpacing = 20                    # 组间距
        self.chart.barSpacing = 1                       # 组内间距
        self.chart.bars.strokeWidth = 0                 # 柱周线宽度
        self.chart.bars.strokeColor = None              # 柱周线颜色
        # 柱标签
        self.chart.barLabels.angle = 90                 # 柱标签旋转90度
        self.chart.barLabelFormat = DecimalFormatter(2) # 柱标签两位小数点
        self.chart.barLabels.boxAnchor ='w'             # 锚点在西
        self.chart.barLabels.boxFillColor = None        # 柱标签没有填充色
        # self.chart.barLabels.boxFillColor = red
        self.chart.barLabels.boxStrokeColor= None       # 柱标签周线没有颜色
        # self.chart.barLabels.boxStrokeColor= red
        self.chart.barLabels.fontName = fontName
        self.chart.barLabels.fontSize = 5
        self.chart.barLabels.dy = 3                     # 向上微调柱标签的位置
        self.chart.barLabels.boxTarget = 'hi'           # 柱标签标在数据柱上
        # self.chart.barLabels.boxTarget = 'lo'           # 柱标签标在数据柱下
        # self.chart.barLabels.boxTarget = 'anti'         # 坐标轴上下,正上负下
        # self.chart.barLabels.boxTarget = 'normal'       # 柱旁,正上负下

        # 数值轴(y轴)
        self.chart.valueAxis.labels.fontName = fontName
        self.chart.valueAxis.labels.fontSize = 8
        self.chart.valueAxis.strokeWidth = 0.25
        self.chart.valueAxis.avoidBoundFrac = 0.5       # 影响数值轴上数据范围
        self.chart.valueAxis.rangeRound ='both'
        # 如何截数值轴的上下值,ceiling(往大了截)还是floor(往小了截),或者两者兼顾both
        self.chart.valueAxis.visibleGrid = False        # y轴出发的格子线不可见
        self.chart.valueAxis.labelTextFormat = DecimalFormatter(0, suffix=None, prefix=None)
        # y轴上刻度值的格式,小数点为0位
        self.chart.valueAxis.labels.boxAnchor='e'       # 锚点在东
        self.chart.valueAxis.labels.dx = -1             # y轴刻度标签向左微调1
        self.chart.valueAxis.visibleTicks = 0           # 刻度线不可见

        # 类别轴(x轴)
        self.chart.categoryAxis.strokeWidth = 0.25
        self.chart.categoryAxis.visibleGrid = False
        self.chart.categoryAxis.visibleTicks = True     # x轴上刻度线可见
        self.chart.categoryAxis.tickUp = 3              # 刻度线向上伸出3
        self.chart.categoryAxis.tickDown = 0            # 刻度线向下伸出0
        self.chart.categoryAxis.labelAxisMode ='low'
        # 刻度标签在整个图表的底部
        # self.chart.categoryAxis.labelAxisMode ='high'
        # 刻度标签在整个图表的顶部
        # self.chart.categoryAxis.labelAxisMode ='axis'
        # 刻度标签在坐标轴旁
        # self.chart.categoryAxis.labelAxisMode ='axispmv'
        # 刻度标签在坐标轴旁,在上在下看数据柱的主要朝向
        self.chart.categoryAxis.labels.textAnchor = 'middle'    # 文字居中
        self.chart.categoryAxis.labels.boxAnchor    = 'n'       # 锚点在北
        self.chart.categoryAxis.labels.fillColor    = black
        self.chart.categoryAxis.labels.angle = 0
        self.chart.categoryAxis.labels.fontName = fontName
        self.chart.categoryAxis.labels.fontSize = 7
        self.chart.categoryAxis.labels.dx = 0           # 刻度标签微调位移
        self.chart.categoryAxis.labels.dy = -2
        self.chart.categoryAxis.categoryNames = ['Quarter', 'YTD', '1-year', '3-year', '5-year']
        # 刻度标签内容

        # 图例
        self._add(self,Legend(),name='legend',validate=None,desc=None)
        self.legend.boxAnchor = 'nw'
        self.legend.deltax = 0
        self.legend.deltay = 10
        self.legend.columnMaximum = 3
        self.legend.fontName = fontName
        self.legend.fontSize = 6
        self.legend.alignment = 'right'
        self.legend.strokeWidth = 0
        self.legend.strokeColor = None
        self.legend.autoXPadding = 0
        self.legend.dx = 7
        self.legend.dy = 7
        self.legend.dxTextSpace = 7
        self.legend.variColumn = True
        self.legend.subCols.minWidth = self.chart.width/2

        self.chart.data = [[-9.0299999999999994, -9.0299999999999994, -4.5800000000000001, 7.2699999999999996, 11.109999999999999],
                           [-9.4399999999999995, -9.4399999999999995, -5.0700000000000003, 5.8499999999999996, 0.0],
                           [2.1699999999999999, 2.1699999999999999, 7.6600000000000001, 0.0, 4.5800000000000001],
                           [-5.1399999999999997, -5.1399999999999997, 0.0, 8.1699999999999999, 11.380000000000001],
                           [-4.8799999999999999, -4.8799999999999999, 0.02, 5.8099999999999996, 8.6999999999999993]]

        series = 'BP', 'Shell Transport & Trading', 'Liberty International', 'Persimmon', 'Royal Bank of Scotland',
        for i, s in enumerate(series):
            self.chart.bars[i].name = s     # 每个数据柱代表的意义
        self.legend.colorNamePairs = Auto(obj=self.chart)
        # 开启自动模式,生成图例色块与名字的一一对应

        # 指定每个数据柱颜色
        colorsList = [PCMYKColor(23,51,0,4,spotName='XXX X',alpha=100), PCMYKColor(100,60,0,50,spotName='7475C',alpha=100),
                      PCMYKColor(100,0,90,50,spotName='7475C',density=40,alpha=100), PCMYKColor(0,100,100,40,spotName='XXX X',alpha=100),
                      PCMYKColor(66,13,0,22,spotName='XXX X',alpha=100), PCMYKColor(0,0,0,40,spotName='XXX X',alpha=100), PCMYKColor(50,0,25,30,spotName='7475C',density=25,alpha=100), PCMYKColor(0,0,0,25,spotName='XXX X',alpha=100)]
        for i, _ in enumerate(self.chart.data):
            self.chart.bars[i].fillColor = colorsList[i]

        # 在图表底部加一条直线
        self.chart.annotations=[lambda c,cA,vA: Line(c.x,c.y,c.x+c.width,c.y,strokeColor=black,strokeWidth=0.5)]
        # 属性annotations的使用参见帖子28 图表的annotation属性

        self.width                  = 400
        self.height                 = 200
        self.chart.x                = 30
        self.chart.y                = 60
        self.legend.x               = 35
        self.legend.y               = 35

if __name__=="__main__":
    BarChart_VLabelsAnnotation().save(formats=['pdf'],outDir='.',fnRoot=None)