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

Incomplete Tick Labels On Matplotlib In Reportlab

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

该文档很长而且涉及面很广,所以我将其精简到最基本的部分。希望我已将其缩减为一个最小的完整且可验证的示例。

我的提炼代码如下:

#!/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()

当我运行此代码时,结果图如下所示:

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

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

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

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

我使用以下资源作为编写代码的指导,同时也作为故障排除的帮助:

Reportlab: Mixing Fixed Content and Flowables

api example code: barchart_demo.py

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

如何并排绘制具有相同 X 坐标的条形图 ('dodged')

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

编辑

根据@Paul H 的评论,我删除了 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')

结果还是一样

我想你想在这里使用 matplotlib 代码和定位器功能,这有助于计算 unused/unlabel-able x-values.

首先你想设置定位器来标记每个整数 ax.xaxis.set_major_locator(plt.MultipleLocator(1))

然后将格式化程序设置为 FuncFormatter 并传入一个函数,该函数将 x-value 和 computes/looks 向上 x-label.

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)