StyleFrame icon indicating copy to clipboard operation
StyleFrame copied to clipboard

AttributeError: 'Series' object has no attribute 'style'

Open buhtz opened this issue 3 years ago • 7 comments
trafficstars

While creating a minimal working example to illustrate a problem I run into this error:

Traceback (most recent call last):
  File "C:\Users\buhtzch\Desktop\x.py", line 25, in <module>
    sf.to_excel(file_path).save()
  File "C:\Users\buhtzch\AppData\Roaming\Python\Python39\site-packages\styleframe\style_frame.py", line 503, in to_excel
    data_df_style = self.data_df.at[index, column].style
  File "C:\Users\buhtzch\AppData\Roaming\Python\Python39\site-packages\pandas\core\generic.py", line 5478, in __getattr__
    return object.__getattribute__(self, name)
AttributeError: 'Series' object has no attribute 'style'

And I don't understand the root of the problem. Maybe I did something wrong or this is a bug or edgy use case?

Version info

Python 3.9.10 (tags/v3.9.10:f2f3f53, Jan 17 2022, 15:14:21) [MSC v.1929 64 bit (AMD64)]
pandas 1.3.0
openpyxl 3.0.9
StyleFrame 4.1

This is the code to reproduce.

#!/usr/bin/env python3
import os
import sys
import pathlib
import pandas
import styleframe
import styleframe.utils

print(styleframe._versions_)

df = pandas.DataFrame(
    data={
        'idx1': list('AABB'),
        'column with long caption': [1234, 345, 33123, 2],
        }
    )
df = df.set_index('idx1')
print(df)

file_path = pathlib.Path.cwd() / 'test.xlsx'

default_style = styleframe.Styler(font_size=14)
sf = styleframe.StyleFrame(df, styler_obj=default_style)

sf.to_excel(file_path).save()
os.system(str(file_path))

EDIT: The exception is not raised when I out-comment the line df = df.set_index('idx1').

buhtz avatar Jun 28 '22 08:06 buhtz

I realized how much Issues I opened today. My apologize. :) I am really willing to support you as much I can.

In case of that Issue the "problem" is located at this line https://github.com/DeepSpace2/StyleFrame/blob/c8a11172d84d4af6eab7c75e7563a00926267765/styleframe/style_frame.py#L503

The data frame in my example has an un-unique index. Pandas does support un-unique indexes. But your current code assumes that the index is unique.

The whole code of .to_excel() is to long (~200 lines). So I won't dive into it because I am scared to break something. But my suggestion would be to not iterate over the index but over the row by count via iloc[]. This makes you independent from the uniqueness of the index.

Beside that problem the to_excel() should be refactored. In the current state it is nearly impossible to understand that code by external contributors. I would give this a try if you aggree.

EDIT: The files in tests directory are without any documentation. I would like to add a test case for that problem but don't know where. I would suggest to minimally add a docstring for each TestCase derived class to make it a bit clearer for new contributors.

buhtz avatar Jun 28 '22 11:06 buhtz

Feel free to open as many issues as you can find :) I appreciate the willingness and any contribution is welcome.

  • I agree that this is a bug, I'll look into using iloc.

  • I agree that to_excel can and should be refactored.

  • What kind of documentation would you expect to see for the tests? Perhaps we can discuss this in a new issue.

DeepSpace2 avatar Jun 28 '22 18:06 DeepSpace2

This exact error also occurs for me when iterating over a list of dataframes.

The code is:

with pd.ExcelWriter(f'_{file}', engine='xlsxwriter') as writer:
    row = 0

    for dataframe, data in zip(tables, metadata):            
        data.to_excel(writer, startrow = row , startcol = 0, index = False, header = False)   
        row = row + data.shape[0]

        sf = StyleFrame(dataframe)
        format1 = Styler(bg_color = '#DCE6F1')
        sf.apply_style_by_indexes(indexes_to_style=sf.index, cols_to_style=[sf.columns[0], sf.columns[2], sf.columns[4]], styler_obj=format1)

        sf.to_excel(writer, startrow = row , startcol = 0, index = False)

        row = row + dataframe.shape[0] + spaces + 1

The subject dataframes in tables do have unique indices.

gribna avatar Jul 07 '22 20:07 gribna

Hi. I can't test right now, but I guess this is due to the usage of 'xlsxwriter' as an engine. Try to use 'openpyxl' which is the only engine that styleframe supports.

I don't see how the iteration in itself can lead to this error.

DeepSpace2 avatar Jul 07 '22 20:07 DeepSpace2

Dear @gribna I also consider that your problem is separate from mine. I would recommend to open a new Issue with your example code. But improve your code and make it work out of the box including sample data. Your code is not clear for us. This would help us to analyze.

I use the "default engine" (openpyxl) set by StyleFrame but the problem occurs.

buhtz avatar Jul 10 '22 13:07 buhtz

I got this issue too when exporting to excel ...

C:\anaconda3\envs\predict-comp-pipeline\lib\site-packages\styleframe\style_frame.py in to_excel(self, excel_writer, sheet_name, allow_protection, right_to_left, columns_to_hide, row_to_add_filters, columns_and_rows_to_freeze, best_fit, **kwargs)
    493             for row_index, index in enumerate(self.data_df.index):
    494                 current_cell = sheet.cell(row=row_index + startrow + (2 if header else 1), column=col_index + startcol + 1)
--> 495                 data_df_style = self.data_df.at[index, column].style
    496                 try:
    497                     if '=HYPERLINK' in str(current_cell.value):

~\AppData\Roaming\Python\Python38\site-packages\pandas\core\generic.py in __getattr__(self, name)
   5137             if self._info_axis._can_hold_identifiers_and_holds_name(name):
   5138                 return self[name]
-> 5139             return object.__getattribute__(self, name)
   5140 
   5141     def __setattr__(self, name: str, value) -> None:

AttributeError: 'Series' object has no attribute 'style'

chunkhai96 avatar Nov 08 '22 07:11 chunkhai96

Also seeing this, confirmed it is due to a duplicate index

odkken avatar Mar 29 '23 15:03 odkken