9
9
from .util import Padding
10
10
11
11
DEFAULT_HEADINGS_STYLE = FontFace (emphasis = "BOLD" )
12
+ DEFAULT_INDEX_STYLE = FontFace (emphasis = "BOLD" )
12
13
13
14
14
15
def draw_box_borders (pdf , x1 , y1 , x2 , y2 , border , fill_color = None ):
@@ -89,6 +90,7 @@ def __init__(
89
90
gutter_height = 0 ,
90
91
gutter_width = 0 ,
91
92
headings_style = DEFAULT_HEADINGS_STYLE ,
93
+ index_style = DEFAULT_INDEX_STYLE ,
92
94
line_height = None ,
93
95
markdown = False ,
94
96
text_align = "JUSTIFY" ,
@@ -97,6 +99,7 @@ def __init__(
97
99
padding = None ,
98
100
outer_border_width = None ,
99
101
num_heading_rows = 1 ,
102
+ num_index_columns = 0 ,
100
103
):
101
104
"""
102
105
Args:
@@ -149,6 +152,8 @@ def __init__(
149
152
self ._wrapmode = wrapmode
150
153
self ._num_heading_rows = num_heading_rows
151
154
self .rows = []
155
+ self .index_style = index_style
156
+ self .n_index_columns = num_index_columns
152
157
153
158
if padding is None :
154
159
self ._padding = Padding .new (0 )
@@ -185,11 +190,14 @@ def __init__(
185
190
self .row (row )
186
191
187
192
def row (self , cells = ()):
188
- "Adds a row to the table. Yields a `Row` object."
193
+ "Adds a row to the table. Yields a `Row` object. Styles first `self.n_index_columns` cells with `self.index_style` "
189
194
row = Row (self ._fpdf )
190
195
self .rows .append (row )
191
- for cell in cells :
192
- row .cell (cell )
196
+ for n , cell in enumerate (cells ):
197
+ if n < self .n_index_columns :
198
+ row .cell (cell , style = self .index_style )
199
+ else :
200
+ row .cell (cell )
193
201
return row
194
202
195
203
def render (self ):
@@ -255,10 +263,10 @@ def render(self):
255
263
# pylint: disable=protected-access
256
264
self ._fpdf ._perform_page_break ()
257
265
# repeat headings on top:
258
- for row_idx in range (self ._num_heading_rows ):
266
+ for row_lbl in range (self ._num_heading_rows ):
259
267
self ._render_table_row (
260
- row_idx ,
261
- self ._get_row_layout_info (row_idx ),
268
+ row_lbl ,
269
+ self ._get_row_layout_info (row_lbl ),
262
270
cell_x_positions = cell_x_positions ,
263
271
)
264
272
elif i and self ._gutter_height :
@@ -646,11 +654,11 @@ def cols_count(self):
646
654
@property
647
655
def column_indices (self ):
648
656
columns_count = len (self .cells )
649
- colidx = 0
650
- indices = [colidx ]
657
+ collbl = 0
658
+ indices = [collbl ]
651
659
for jj in range (columns_count - 1 ):
652
- colidx += self .cells [jj ].colspan
653
- indices .append (colidx )
660
+ collbl += self .cells [jj ].colspan
661
+ indices .append (collbl )
654
662
return indices
655
663
656
664
def cell (
@@ -726,3 +734,49 @@ class Cell:
726
734
727
735
def write (self , text , align = None ):
728
736
raise NotImplementedError ("Not implemented yet" )
737
+
738
+
739
+ def format_label_tuples (lbl , char = " " ):
740
+ """
741
+ Formats columns and indexes to match DataFrame formatting.
742
+ """
743
+ indexes = [lbl [0 ]]
744
+ for i , j in zip (lbl , lbl [1 :]):
745
+ next_label = []
746
+ for i_ , j_ in zip (i , j ):
747
+ if j_ == i_ :
748
+ next_label .append (char )
749
+ else :
750
+ next_label .append (j_ )
751
+ indexes .append (tuple (next_label ))
752
+ return indexes
753
+
754
+
755
+ def add_labels_to_data (data , indexes , columns , include_index : bool = True , char = " " ):
756
+ """Combines index and column labels with data for table output"""
757
+ if include_index :
758
+ index_header_padding = [tuple (char ) * len (indexes [0 ])] * len (columns [0 ])
759
+ formatted_indexes = format_label_tuples (indexes )
760
+ new_values = []
761
+ for i , v in zip (formatted_indexes , data ):
762
+ new_values .append (list (i ) + list (v ))
763
+ formatted_columns = [
764
+ list (c )
765
+ for c in zip (* format_label_tuples (index_header_padding + list (columns )))
766
+ ]
767
+ new_data = formatted_columns + new_values
768
+
769
+ else :
770
+ formatted_columns = [list (c ) for c in zip (* format_label_tuples (list (columns )))]
771
+ new_data = formatted_columns + data .tolist ()
772
+
773
+ return new_data
774
+
775
+
776
+ def format_dataframe (df , include_index : bool = True ):
777
+ """Fully formats a dataframe for conversion into pdf"""
778
+ data = df .map (str ).values
779
+ columns = df .columns
780
+ indexes = df .index
781
+ table_data = add_labels_to_data (data , indexes , columns , include_index = include_index )
782
+ return table_data
0 commit comments