[reportlab-users] Table cell too large vertically

3,956 views
Skip to first unread message

Blake McBride

unread,
Mar 22, 2016, 10:50:40 AM3/22/16
to reportl...@lists2.reportlab.com
Hi,

I am running reportlab 3.3.0 with Python 2.7.6.  I've defined a table.  When the number of rows exceeds the page size, reportlab correctly causes a new page to start.  Great.  The problem I am having is sometimes the vertical size of a single cell exceeds the vertical space of the page.  I would expect reportlab to print as much of the row as it can on the page, and then print the rest of the same row on a new page.  In other words, if the size of a single row exceeds the vertical space on a whole page, reporlab should split the extra large row into multiple pages rather than issue an exception.  The line that causes the error is:

doc.build(elements, onFirstPage=__pageFooter, onLaterPages=__pageFooter)

 The error I am getting is:

<<class 'reportlab.platypus.doctemplate.LayoutError'>
Traceback (most recent call last):
  File "/home/blake/XXX/YYYY/report.py", line 342, in report
    try:
  File "/home/blake/XXX/YYYY/venv/local/lib/python2.7/site-packages/reportlab/platypus/doctemplate.py", line 1200, in build
    BaseDocTemplate.build(self,flowables, canvasmaker=canvasmaker)
  File "/home/blake/XXX/YYYY/venv/local/lib/python2.7/site-packages/reportlab/platypus/doctemplate.py", line 956, in build
    self.handle_flowable(flowables)
  File "/home/blake/XXX/YYYY/venv/local/lib/python2.7/site-packages/reportlab/platypus/doctemplate.py", line 851, in handle_flowable
    raise LayoutError(ident)
LayoutError: Flowable <Table@0x7FC37B5DD290 20 rows x 5 cols(tallest row 558)> with cell(0,0) containing
'Col Heading 3' (705 x 4788), tallest cell 558.0 points,  too large on page 2 in frame 'normal'(636.0 x 456.0*) of template 'Later'


Any help would sure be appreciated.

Blake McBride

Robin Becker

unread,
Mar 22, 2016, 11:17:17 AM3/22/16
to reportlab-users
On 22/03/2016 14:50, Blake McBride wrote:
> Hi,
>
>........
> and then print the rest of the same row on a new page. In other words, if
> the size of a single row exceeds the vertical space on a whole page,
> reporlab should split the extra large row into multiple pages rather than
> issue an exception. The line that causes the error is:
>
Hi Blake,


Unfortunately we don't split cells; your only options are to reduce the size of
the fonts in the problematic cell or use some other method to reduce the cell's
height.
--
Robin Becker
_______________________________________________
reportlab-users mailing list
reportl...@lists2.reportlab.com
https://pairlist2.pair.net/mailman/listinfo/reportlab-users

Blake McBride

unread,
Mar 22, 2016, 12:11:45 PM3/22/16
to reportlab-users
I can automate a solution if I know two things:

1.  How tall a given block of text would be

2.  Max cell height

Can I get these?

Thanks.

Blake

Blake McBride

unread,
Mar 22, 2016, 2:20:44 PM3/22/16
to reportlab-users
The amount of data varies widely and is user input.  I can't predict the length.  So, reducing the font won't work.

I tried to ball park the max size and split the data myself onto several table rows.  That works but is as ugly as can be.  I never know where on the page the system will be when encountering a row that is too big, so I don't know how much space I have left.

Having written several report generators over the years, I think the algorithm should be:

if row is too big for an entire page
    while more text
        print as much as you can on the current page
        reduce text by what was printed
        page break
else if row is too big for the current page (but small enough for a new page)
    page break
    print row
else
    print row

Other than this fix on the reportlab end, I don't think there is a way for me to create a decently laid out report in this case.

Thanks.

Blake McBride



On Tue, Mar 22, 2016 at 10:17 AM, Robin Becker <ro...@reportlab.com> wrote:

Tim Roberts

unread,
Mar 22, 2016, 2:27:39 PM3/22/16
to reportlab-users
Blake McBride wrote:
>
> Having written several report generators over the years, I think the
> algorithm should be:
>
> if row is too big for an entire page
> while more text
> print as much as you can on the current page
> reduce text by what was printed
> page break
> else if row is too big for the current page (but small enough for a
> new page)
> page break
> print row
> else
> print row

But remember, that's easier said than done. You might have word wrap in
every cell going across. For this to work, you would have to be doing
that word wrapping on every cell in parallel. When one cell detects
that it's about to exceed the page, you'd need to send a signal to all
of the other cells telling them to fill out as much as they can, then
pause until after the page break, then resume. And what about paragraph
widow control? That requires backtracking.

There's a lot of state to carry around.

--
Tim Roberts, ti...@probo.com
Providenza & Boekelheide, Inc.

Blake McBride

unread,
Mar 22, 2016, 2:55:54 PM3/22/16
to reportlab-users
Yes, with multiple columns it is a little more complex.  But, this is a serious problem, and must be handled at the reportlab level if it is to be handled correctly.  I'd think for someone familiar with the code this could be a two or four hour project.  Well worth the effort to solve a fundamental issue.  Just my 2 cents...

As it is, I guesstimated the max length and split large rows into multiple rows.  It is an ugly solution but allows me to move forward.

Thanks.

Blake McBride

Andy Robinson

unread,
Mar 23, 2016, 3:55:44 AM3/23/16
to reportlab-users
Blake, we agree totally that it SHOULD be fixed, we just haven't been
able to do it in about 12 years. If you can crack it in 2-4 hours,
even after a week of familiarisation with the code, we would be
delighted to hire you to do it and you could pretty much name your
hourly rate ;-)

The ReportLab library does no backtracking. It can't say "that did
not work, I'll back up and try again". This was a design decision to
get decent speed out of a large Python object model. Splitting works
by returning two table objects, one to go on this page and one for the
next, with suitably modified styles for the "next page" table. It
also has to handle horizontal and vertical column spanning, the fact
that a table cell can contain anything (including more tables, with
padding around them), some cells having defined width and some being
flexible. If you split one cell you then have to figure out, for
each cell alongside it (some of which may span rows) how much of their
content must go on the first page or second page.

We looked at the algorithms used to do table layout in browsers and
they are not simple (and require C+-like speeds and multiple tries at
things), and they don't even handle splitting.

Now it may well be that a split could be possible in the special case
that there was no spanning alongside.

As for a better workaround: If your table content is just text, and
you know the width, you can work out the size of a paragraph quite
easily and accurately by calling wrap() and passing in the width and a
larger-than-needed height; it will reply with the width and heigh it
actually needs. So you could pre-scan all your content and break
into smaller chunks before building rh table. Ugly, but could be
quite accurate and would not complicate rendering.

- Andy
Reply all
Reply to author
Forward
0 new messages