Незавершенные метки тиков на Matplotlib в Reportlab - PullRequest
0 голосов
/ 14 мая 2019

Я работаю над созданием pdf-документа, содержащего графики, используя reportlab и matplotlib, и недавно у меня возникла проблема, из-за которой я не могу добиться того, чтобы тиковые метки по оси x соответствовали данным на простой сторонерядом "барный участок.

Документ довольно длинный и сложный, поэтому я вернул его к основам.Надеюсь, Айв сократил это до минимального полного и проверяемого примера.

Мой перегруженный код выглядит следующим образом:

#!/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 пытался быть полезным и подгонял числовые данные к диапазону, но только находил пересечение двух списков, поэтому я представил его в виде списка строк, но проблема сохраняется.

Я посмотрел вокругnet и SO для указателей, но, кажется, не могу найти что-либо непосредственно релевантное.

Я использовал следующие ресурсы в качестве руководства для написания моего кода, а также в качестве помощи по устранению неполадок:

Reportlab:Смешивание фиксированного содержимого и потоковых таблиц

пример кода API: barchart_demo.py

, и я также использовал этот вопрос SO в качестве руководства

Как построить гистограммуs с одинаковыми координатами X рядом («уклонено»)

Может кто-нибудь объяснить, почему это происходит?

РЕДАКТИРОВАТЬ

Согласно комментарию @Пол Х, я убрал код отчета и все еще получаю тот же результат.

Обновленный код следует:

#!/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 Ответ

1 голос
/ 14 мая 2019

Я думаю, что вы хотите использовать здесь функцию тикера и локатора 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

...