Skip to content

Instantly share code, notes, and snippets.

@o2b-ru
Last active January 16, 2024 06:17
Show Gist options
  • Save o2b-ru/9434e212d1e1fc7db9370c49238ddbbd to your computer and use it in GitHub Desktop.
Save o2b-ru/9434e212d1e1fc7db9370c49238ddbbd to your computer and use it in GitHub Desktop.
BigDataTable faster LongTable on the big data (reportlab==3.5.23)
import reportlab
from reportlab import platypus
from reportlab.lib.utils import annotateException, IdentStr, flatten, isStr, asNative, strTypes
class BigDataTable(platypus.Table):
def _splitRows(self, availHeight):
n = self._getFirstPossibleSplitRowPosition(availHeight)
repeatRows = self.repeatRows
if n <= (repeatRows if isinstance(repeatRows, int) else (max(repeatRows) + 1)): return []
lim = len(self._rowHeights)
if n == lim: return [self]
lo = self._rowSplitRange
if lo:
lo, hi = lo
if lo < 0: lo += lim
if hi < 0: hi += lim
if n > hi:
return self._splitRows(availHeight - sum(self._rowHeights[hi:n]))
elif n < lo:
return []
repeatCols = self.repeatCols
splitByRow = self.splitByRow
data = self._cellvalues
# we're going to split into two superRows
ident = self.ident
if ident: ident = IdentStr(ident)
splitH = self._rowHeights
R0 = self.__class__(data[:n], colWidths=self._colWidths, rowHeights=splitH[:n],
repeatRows=repeatRows, repeatCols=repeatCols,
splitByRow=splitByRow, normalizedData=1, cellStyles=self._cellStyles[:n],
ident=ident,
spaceBefore=getattr(self, 'spaceBefore', None),
longTableOptimize=0)
nrows = self._nrows
ncols = self._ncols
# copy the commands
A = []
# hack up the line commands
for op, (sc, sr), (ec, er), weight, color, cap, dash, join, count, space in self._linecmds:
if isinstance(sr, strTypes) and sr.startswith('split'):
A.append((op, (sc, sr), (ec, sr), weight, color, cap, dash, join, count, space))
if sr == 'splitlast':
sr = er = n - 1
elif sr == 'splitfirst':
sr = n
er = n
if sc < 0: sc += ncols
if ec < 0: ec += ncols
if sr < 0: sr += nrows
if er < 0: er += nrows
if op in ('BOX', 'OUTLINE', 'GRID'):
if sr < n and er >= n:
# we have to split the BOX
A.append(('LINEABOVE', (sc, sr), (ec, sr), weight, color, cap, dash, join, count, space))
A.append(('LINEBEFORE', (sc, sr), (sc, er), weight, color, cap, dash, join, count, space))
A.append(('LINEAFTER', (ec, sr), (ec, er), weight, color, cap, dash, join, count, space))
A.append(('LINEBELOW', (sc, er), (ec, er), weight, color, cap, dash, join, count, space))
if op == 'GRID':
A.append(('LINEBELOW', (sc, n - 1), (ec, n - 1), weight, color, cap, dash, join, count, space))
A.append(('LINEABOVE', (sc, n), (ec, n), weight, color, cap, dash, join, count, space))
A.append(('INNERGRID', (sc, sr), (ec, er), weight, color, cap, dash, join, count, space))
else:
A.append((op, (sc, sr), (ec, er), weight, color, cap, dash, join, count, space))
elif op == 'INNERGRID':
if sr < n and er >= n:
A.append(('LINEBELOW', (sc, n - 1), (ec, n - 1), weight, color, cap, dash, join, count, space))
A.append(('LINEABOVE', (sc, n), (ec, n), weight, color, cap, dash, join, count, space))
A.append((op, (sc, sr), (ec, er), weight, color, cap, dash, join, count, space))
elif op == 'LINEBELOW':
if sr < n and er >= (n - 1):
A.append(('LINEABOVE', (sc, n), (ec, n), weight, color, cap, dash, join, count, space))
A.append((op, (sc, sr), (ec, er), weight, color, cap, dash, join, count, space))
elif op == 'LINEABOVE':
if sr <= n and er >= n:
A.append(('LINEBELOW', (sc, n - 1), (ec, n - 1), weight, color, cap, dash, join, count, space))
A.append((op, (sc, sr), (ec, er), weight, color, cap, dash, join, count, space))
else:
A.append((op, (sc, sr), (ec, er), weight, color, cap, dash, join, count, space))
R0._cr_0(n, A, nrows)
R0._cr_0(n, self._bkgrndcmds, nrows, _srflMode=True)
R0._cr_0(n, self._spanCmds, nrows)
R0._cr_0(n, self._nosplitCmds, nrows)
for c in self._srflcmds:
R0._addCommand(c)
if c[1][1] != 'splitlast': continue
(sc, sr), (ec, er) = c[1:3]
R0._addCommand((c[0],) + ((sc, n - 1), (ec, n - 1)) + tuple(c[3:]))
if ident: ident = IdentStr(ident)
if repeatRows:
if isinstance(repeatRows, int):
iRows = data[:repeatRows]
nRepeatRows = repeatRows
iRowH = splitH[:repeatRows]
iCS = self._cellStyles[:repeatRows]
else:
# we have a list of repeated rows eg (1,3)
repeatRows = list(sorted(repeatRows))
iRows = [data[i] for i in repeatRows]
nRepeatRows = len(repeatRows)
iRowH = [splitH[i] for i in repeatRows]
iCS = [self._cellStyles[i] for i in repeatRows]
R1 = self.__class__(iRows + data[n:], colWidths=self._colWidths,
rowHeights=iRowH + splitH[n:],
repeatRows=nRepeatRows, repeatCols=repeatCols,
splitByRow=splitByRow, normalizedData=1,
cellStyles=iCS + self._cellStyles[n:],
ident=ident,
spaceAfter=getattr(self, 'spaceAfter', None),
longTableOptimize=self._longTableOptimize,
)
R1._cr_1_1(n, nRepeatRows, A)
R1._cr_1_1(n, nRepeatRows, self._bkgrndcmds, _srflMode=True)
R1._cr_1_1(n, nRepeatRows, self._spanCmds)
R1._cr_1_1(n, nRepeatRows, self._nosplitCmds)
else:
R1 = self.__class__(data[n:], colWidths=self._colWidths, rowHeights=splitH[n:],
repeatRows=repeatRows, repeatCols=repeatCols,
splitByRow=splitByRow, normalizedData=1, cellStyles=self._cellStyles[n:],
ident=ident,
spaceAfter=getattr(self, 'spaceAfter', None),
longTableOptimize=self._longTableOptimize,
)
R1._cr_1_0(n, A)
R1._cr_1_0(n, self._bkgrndcmds, _srflMode=True)
R1._cr_1_0(n, self._spanCmds)
R1._cr_1_0(n, self._nosplitCmds)
for c in self._srflcmds:
R1._addCommand(c)
if c[1][1] != 'splitfirst': continue
(sc, sr), (ec, er) = c[1:3]
R1._addCommand((c[0],) + ((sc, 0), (ec, 0)) + tuple(c[3:]))
R0.hAlign = R1.hAlign = self.hAlign
R0.vAlign = R1.vAlign = self.vAlign
self.onSplit(R0)
self.onSplit(R1)
return [R0, R1]
@kapsonic
Copy link

Hey Great work and it saved my day.

Can you please explain it a bit more about why it works so well?

@o2b-ru
Copy link
Author

o2b-ru commented Dec 19, 2019

Performance debugging!

Look at the highlighted values before (left) and after (right):

compare5advanced

https://stackoverflow.com/a/59372754/1496088

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment