Skip to content

Commit f13d093

Browse files
author
locojaydev
committed
excelformatter handles multiindex, aliases
1 parent c99dc49 commit f13d093

File tree

1 file changed

+93
-13
lines changed

1 file changed

+93
-13
lines changed

pandas/core/format.py

+93-13
Original file line numberDiff line numberDiff line change
@@ -717,15 +717,25 @@ class ExcelFormatter(object):
717717
Format string for floating point numbers
718718
cols : sequence, optional
719719
Columns to write
720+
header : boolean or list of string, default True
721+
Write out column names. If a list of string is given it is
722+
assumed to be aliases for the column names
720723
index : boolean, default True
721724
output row names (index)
725+
index_label : string or sequence, default None
726+
Column label for index column(s) if desired. If None is given, and
727+
`header` and `index` are True, then the index names are used. A
728+
sequence should be given if the DataFrame uses MultiIndex.
722729
"""
723730

724731
def __init__(self,
725732
df,
726733
na_rep='',
727734
float_format=None,
728-
cols=None
735+
cols=None,
736+
header=True,
737+
index=True,
738+
index_label=None
729739
):
730740
self.df = df
731741
self.rowcounter = 0
@@ -734,34 +744,58 @@ def __init__(self,
734744
if cols is None:
735745
self.columns = df.columns
736746
self.float_format = float_format
747+
self.index = index
748+
self.index_label = index_label
749+
self.header = header
737750

738751
def _format_value(self, val):
739752
if lib.checknull(val):
740753
val = self.na_rep
741754
if self.float_format is not None and com.is_float(val):
742-
val = self.float_format % val
755+
val = float(self.float_format % val)
743756
return val
744757

745758
def _format_header_mi(self):
746759
levels = self.columns.format(sparsify=True, adjoin=False,
747760
names=False)
748761
level_lenghts = _get_level_lengths(levels)
762+
coloffset = 0
763+
if isinstance(self.df.index, MultiIndex):
764+
coloffset = len(self.df.index[0]) - 1
765+
749766
for lnum, (records, values) in enumerate(zip(level_lenghts,
750767
levels)):
751768
name = self.columns.names[lnum]
752-
yield ExcelCell(lnum, 0, name, header_style)
769+
yield ExcelCell(lnum, coloffset, name, header_style)
753770
for i in records:
754771
if records[i] > 1:
755-
yield ExcelCell(lnum, i + 1, values[i],
756-
header_style, lnum, i + records[i])
772+
yield ExcelCell(lnum,coloffset + i + 1, values[i],
773+
header_style, lnum, coloffset + i + records[i])
757774
else:
758-
yield ExcelCell(lnum, i + 1, values[i], header_style)
775+
yield ExcelCell(lnum, coloffset + i + 1, values[i], header_style)
759776

760777
self.rowcounter = lnum
761778

762779
def _format_header_regular(self):
763-
for colindex, colname in enumerate(self.columns):
764-
yield ExcelCell(self.rowcounter, colindex, colname, header_style)
780+
has_aliases = isinstance(self.header, (tuple, list, np.ndarray))
781+
if has_aliases or self.header:
782+
coloffset = 0
783+
if self.index:
784+
coloffset = 1
785+
if isinstance(self.df.index, MultiIndex):
786+
coloffset = len(self.df.index[0])
787+
788+
colnames = self.columns
789+
if has_aliases:
790+
if len(self.header) != len(self.columns):
791+
raise ValueError(('Writing %d cols but got %d aliases'
792+
% (len(self.columns), len(self.header))))
793+
else:
794+
colnames = self.header
795+
796+
for colindex, colname in enumerate(colnames):
797+
yield ExcelCell(self.rowcounter, colindex + coloffset, colname,
798+
header_style)
765799

766800
def _format_header(self):
767801
if isinstance(self.columns, MultiIndex):
@@ -781,27 +815,73 @@ def _format_header(self):
781815

782816
def _format_body(self):
783817

784-
if isinstance(self.df.columns, MultiIndex):
818+
if isinstance(self.df.index, MultiIndex):
785819
return self._format_hierarchical_rows()
786820
else:
787821
return self._format_regular_rows()
788822

789823
def _format_regular_rows(self):
790824
self.rowcounter += 1
825+
826+
coloffset = 0
827+
#output index and index_label?
828+
if self.index:
829+
#chek aliases
830+
#if list only take first as this is not a MultiIndex
831+
if self.index_label and isinstance(self.index_label,
832+
(list, tuple, np.ndarray)):
833+
index_label = self.index_label[0]
834+
#if string good to go
835+
elif self.index_label and isinstance(self.index_label, str):
836+
index_label = self.index_label
837+
else:
838+
index_label = self.df.index.names[0]
839+
840+
if index_label:
841+
yield ExcelCell(self.rowcounter, 0,
842+
index_label, header_style)
843+
self.rowcounter += 1
844+
845+
#write index_values
846+
index_values = self.df.index
847+
coloffset = 1
848+
for idx, idxval in enumerate(index_values):
849+
yield ExcelCell(self.rowcounter + idx, 0, idxval, header_style)
850+
791851
for colidx, colname in enumerate(self.columns):
792852
series = self.df[colname]
793853
for i, val in enumerate(series):
794-
yield ExcelCell(self.rowcounter + i, colidx, val)
854+
yield ExcelCell(self.rowcounter + i, colidx + coloffset, val)
795855

796856
def _format_hierarchical_rows(self):
797857
self.rowcounter += 1
798-
for idx, idxval in enumerate(self.df.index):
799-
yield ExcelCell(self.rowcounter + idx, 0, idxval, header_style)
858+
859+
gcolidx = 0
860+
#output index and index_label?
861+
if self.index:
862+
index_labels = self.df.index.names
863+
#check for aliases
864+
if self.index_label and isinstance(self.index_label,
865+
(list, tuple, np.ndarray)):
866+
index_labels = self.index_label
867+
868+
#if index labels are not empty go ahead and dump
869+
if filter(lambda x: x is not None, index_labels):
870+
for cidx, name in enumerate(index_labels):
871+
yield ExcelCell(self.rowcounter, cidx,
872+
name, header_style)
873+
self.rowcounter += 1
874+
875+
for indexcolvals in zip(*self.df.index):
876+
for idx, indexcolval in enumerate(indexcolvals):
877+
yield ExcelCell(self.rowcounter + idx, gcolidx,
878+
indexcolval, header_style)
879+
gcolidx += 1
800880

801881
for colidx, colname in enumerate(self.columns):
802882
series = self.df[colname]
803883
for i, val in enumerate(series):
804-
yield ExcelCell(self.rowcounter + i, colidx + 1, val)
884+
yield ExcelCell(self.rowcounter + i, gcolidx + colidx, val)
805885

806886
def get_formatted_cells(self):
807887
for cell in itertools.chain(self._format_header(),

0 commit comments

Comments
 (0)