Reportlab中Matplotlib上的刻度标记不完整

时间:2019-05-14 16:03:12

标签: python matplotlib plot bar-chart reportlab

我正在使用reportlab和matplotlib创建包含绘图的pdf文档,最近遇到了一个问题,即我似乎无法使x轴刻度标签与简单的“一边”数据正确对齐并排”条形图。

该文档很长且涉及很多,因此我将其剥离为基本内容。希望Ive将其缩减为一个最小的完整且可验证的示例。

我的提炼代码如下:

#!/usr/bin/env python3

import numpy as np
import reportlab.lib, reportlab.platypus
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import mm, inch, cm
from reportlab.pdfgen import canvas
import matplotlib.pyplot as plt
from io import BytesIO

class flowable(reportlab.platypus.Flowable):
    def __init__(self, imgdata):
        reportlab.platypus.Flowable.__init__(self)
        self.img = reportlab.lib.utils.ImageReader(imgdata)

    def draw(self):
        self.canv.drawImage(self.img, 0, 0, height = -4.5*inch, width=7*inch)

class LetterMaker(object):
    """"""

    #----------------------------------------------------------------------

    def __init__(self, pdf_file):
        self.c = canvas.Canvas(pdf_file, pagesize=A4)
        self.styles = getSampleStyleSheet()
        self.width, self.height = A4

    #----------------------------------------------------------------------
    def createDocument(self):
        """"""
        rx = [14, 44, 16, 155, 214, 187, 222, 405, 314, 199]
        tx = [56, 92, 103, 28, 22, 12, 24, 75, 20, 15]
        dates = [4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
        labels = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
        fig = plt.figure()
        ax = fig.add_subplot(1, 1, 1) # nrows, ncols, index
        indices = np.arange(len(dates))
        bar_width = np.min(np.diff(indices))/3.
        ax.axes.set_xticklabels(labels)
        plt.bar(indices-bar_width/2, rx, bar_width)
        plt.bar(indices+bar_width/2, tx, bar_width)
        imgdata = BytesIO()
        fig.savefig(imgdata, format='png', edgecolor='#79b85f', facecolor=fig.get_facecolor())
        imgdata.seek(0)  # rewind the data

        pic = flowable(imgdata)
        pic.wrapOn(self.c, self.width, self.height)
        pic.drawOn(self.c, *self.coord( 2, 14, cm))


    def coord(self, x, y, unit=1):
        x, y = x * unit, self.height -  y * unit
        return x, y

    def savePDF(self):
        """"""
        self.c.save()

if __name__ == "__main__":
    doc = LetterMaker("testfile.pdf")
    doc.createDocument()
    doc.savePDF()

运行此代码时,结果图如下:

enter image description here

我无法解释为什么x轴标签没有遵循标签列表中的完整设置。

最初,日期数据是一个整数列表。

我怀疑matplotlib试图提供帮助并将数值数据拟合到该范围,但只找到两个列表的交集,因此我将其作为字符串列表提供,但问题仍然存在。

我一直在网上寻找指针,但是似乎找不到任何直接相关的东西。

我已使用以下资源作为编写代码的指南,以及作为故障排除的帮助:

Reportlab: Mixing Fixed Content and Flowables

api example code: barchart_demo.py

而且我也使用了这个SO问题作为指导

How to plot bar graphs with same X coordinates side by side ('dodged')

有人可以解释为什么会这样吗?

编辑

根据@Paul H的评论,Ive除去了reportlab代码,仍然得到相同的结果。

更新后的代码如下:

#!/usr/bin/env python3

import matplotlib.pyplot as plt
import numpy as np

rx = [14, 44, 16, 155, 214, 187, 222, 405, 314, 199]
tx = [56, 92, 103, 28, 22, 12, 24, 75, 20, 15]
dates = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
labels = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1) # nrows, ncols, index
indices = np.arange(len(dates))
bar_width = np.min(np.diff(indices))/3.
ax.axes.set_xticklabels(labels)
plt.bar(indices-bar_width/2, rx, bar_width)
plt.bar(indices+bar_width/2, tx, bar_width)
fig.savefig('plot.png')

结果仍然相同。

1 个答案:

答案 0 :(得分:1)

我认为您想在此处使用matplotlib代码和定位器功能,这有助于计算未使用/无法标记的x值。

首先,您要设置定位器以标记每个整数 ax.xaxis.set_major_locator(plt.MultipleLocator(1))

然后将格式程序设置为FuncFormatter,并传入一个采用x值并计算/查找x标签的函数。

import matplotlib.pyplot as plt
import numpy as np

rx = [14, 44, 16, 155, 214, 187, 222, 405, 314, 199]
tx = [56, 92, 103, 28, 22, 12, 24, 75, 20, 15]
dates = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
labels = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1) # nrows, ncols, index
indices = np.arange(len(dates))
bar_width = np.min(np.diff(indices))/3.
ax.bar(indices-bar_width/2, rx, bar_width)
ax.bar(indices+bar_width/2, tx, bar_width)


@plt.FuncFormatter
def ticks(x, pos):
    try:
        return labels[int(x)]
    except IndexError:
        return ''

ax.xaxis.set_major_locator(plt.MultipleLocator(1))
ax.xaxis.set_major_formatter(ticks)

enter image description here