ERROR in PYTHON type object 'Sheet' has no attribute 'add' - pandas

I have error in python code. I am trying split workbook to different sheets based on column value, below is the code.
import pandas as pd
import os
from xlwings import Book, Range, Sheet
path = ('C:\Dell')
worksheet = ('FILE.xlsx')
sheet =('Temporary_Table')
column = ('SERIAL_NUMBER')
workbook = os.path.join(path, worksheet)
wb = Book(workbook)
data = pd.DataFrame(pd.read_excel(workbook, sheet, index_col=None, na_values=[0]))
data.sort_values(column, axis = 0, inplace = True)
data = pd.DataFrame(pd.read_excel(workbook, sheet, index_col=None, na_values=[0]))
data.sort_values(column, axis = 0, inplace = True)
split = data.groupby(column)
for i in split.groups:
Sheet.add()
Range('A1', index = False).value = split.get_group(i)
it keeps giving me
type object 'Sheet' has no attribute 'add'

Related

openpyxl format numerical row

Good morning, via webscraping I create a table with openpyxl that creates a monthly calendar for me, the table works, only the format does not match, I would like the added rows to be in numeric format.
try:
wb = load_workbook(filename)
ws = wb.worksheets[0] # select first worksheet
except FileNotFoundError:
headers_row = ['Datum','Dienst','Funktion','Von','Bis','Schichtdauer','Bezahlte Zeit (Studen)','Bezahlte Zeit (Minuten)','Zeit Konvertierung','Überzeit (ab 10 St.)','Nachtzeitzuschlag.','Nachtdienstentschädigung','Wegzeiten']
wb = Workbook()
ws = wb.active
ws.append(headers_row)
wb.save(filename)
ws.append([f'{Datetime}',f'{string1}'f'{tagesinfo2}',f'{soup_funktion}',f'{StartTime}',f'{EndTime}',f'{Schichtdauer}',f'{Bezahltezeit_Stunden}',f'{Bezahltezeit_Minuten}',f'{emptycell}',f'{emptycell}',f'{NachtArbeitZeit / 60 * 10}',f'{nachtszulage}',f'{wegzeiten}'])
for cols in ws.iter_cols( ):
if cols[-1].value:
cols[-1].border = Border(left=Side(style='thin'),right=Side(style='thin'),top=Side(style='thin'),bottom=Side(style='thin'))
wb.save(filename)
wb.close()

Is it possible to append a StyleFrame to an existing excel worksheet?

I was wondering if it was possible to write a StyleFrame to an arbitrary position in an existing excel worksheet while maintaining the original formatting and styling of pre-existing cells?
E.g In the example below, I'd like to set the output of the Styleframe to start from cell 'A9' while maintaining the formatting and coloring of the other cells (Cells 'A1','A2','A3' etc):
So user #MaxU has a helpful answer over here outlining a function that appends regular dataframes to arbitrary positions in an existing excel worksheet. With some minor changes I've been able to modify this function to work on styleframes. Note that while the modified function successfully writes most cell properties into existing worksheets for some reason it does not copy cell alignments over. So I have hard-coded the Alignments of appended cells to be top,left and wrapped. Please see the modified code below:
from pathlib import Path
from copy import copy
from typing import Union, Optional
import numpy as np
import pandas as pd
import openpyxl
from openpyxl import load_workbook
from openpyxl.utils import get_column_letter
from styleframe import StyleFrame
from openpyxl.styles.alignment import Alignment
def copy_excel_cell_range(
src_ws: openpyxl.worksheet.worksheet.Worksheet,
min_row: int = None,
max_row: int = None,
min_col: int = None,
max_col: int = None,
tgt_ws: openpyxl.worksheet.worksheet.Worksheet = None,
tgt_min_row: int = 1,
tgt_min_col: int = 1,
with_style: bool = True
) -> openpyxl.worksheet.worksheet.Worksheet:
if tgt_ws is None:
tgt_ws = src_ws
# https://stackoverflow.com/a/34838233/5741205
for row in src_ws.iter_rows(min_row=min_row, max_row=max_row,
min_col=min_col, max_col=max_col):
for cell in row:
tgt_cell = tgt_ws.cell(
row=cell.row + tgt_min_row - 1,
column=cell.col_idx + tgt_min_col - 1,
value=cell.value
)
if with_style and cell.has_style:
# tgt_cell._style = copy(cell._style)
tgt_cell.font = copy(cell.font)
tgt_cell.border = copy(cell.border)
tgt_cell.fill = copy(cell.fill)
tgt_cell.number_format = copy(cell.number_format)
tgt_cell.protection = copy(cell.protection)
tgt_cell.alignment = Alignment(horizontal='left', vertical='top',wrapText=True)
return tgt_ws
def append_sf_to_excel(
filename: Union[str, Path],
sf: StyleFrame,
sheet_name: str = 'Sheet1',
startrow: Optional[int] = None,
max_col_width: int = 30,
autofilter: bool = False,
fmt_int: str = "#,##0",
fmt_float: str = "#,##0.00",
fmt_date: str = "yyyy-mm-dd",
fmt_datetime: str = "yyyy-mm-dd hh:mm",
truncate_sheet: bool = False,
storage_options: Optional[dict] = None,
**to_excel_kwargs
) -> None:
def set_column_format(ws, column_letter, fmt):
for cell in ws[column_letter]:
cell.number_format = fmt
filename = Path(filename)
file_exists = filename.is_file()
# process parameters
# calculate first column number
# if the sf will be written using `index=True`, then `first_col = 2`, else `first_col = 1`
first_col = int(to_excel_kwargs.get("index", True)) + 1
# ignore [engine] parameter if it was passed
if 'engine' in to_excel_kwargs:
to_excel_kwargs.pop('engine')
# save content of existing sheets
if file_exists:
wb = load_workbook(filename)
sheet_names = wb.sheetnames
sheet_exists = sheet_name in sheet_names
sheets = {ws.title: ws for ws in wb.worksheets}
with StyleFrame.ExcelWriter(
filename.with_suffix(".xlsx"),
mode="a" if file_exists else "w",
if_sheet_exists="new" if file_exists else None,
date_format=fmt_date,
datetime_format=fmt_datetime,
storage_options=storage_options
) as writer:
if file_exists:
# try to open an existing workbook
writer.book = wb
# get the last row in the existing Excel sheet
# if it was not specified explicitly
# for row in wb['Sheet1'].iter_rows():
# for cell in row:
# print(f'{cell.alignment}\n\n')
if startrow is None and sheet_name in writer.book.sheetnames:
startrow = writer.book[sheet_name].max_row
# truncate sheet
if truncate_sheet and sheet_name in writer.book.sheetnames:
# index of [sheet_name] sheet
idx = writer.book.sheetnames.index(sheet_name)
# remove [sheet_name]
writer.book.remove(writer.book.worksheets[idx])
# create an empty sheet [sheet_name] using old index
writer.book.create_sheet(sheet_name, idx)
# copy existing sheets
writer.sheets = sheets
else:
# file doesn't exist, we are creating a new one
startrow = 0
# write out the DataFrame to an ExcelWriter
sf.to_excel(writer, sheet_name=sheet_name)
worksheet = writer.sheets[sheet_name]
if autofilter:
worksheet.auto_filter.ref = worksheet.dimensions
for xl_col_no, dtyp in enumerate(sf.data_df.dtypes, first_col):
col_no = xl_col_no - first_col
width = max(sf.iloc[:, col_no].astype(str).str.len().max(),
len(sf.columns[col_no]) + 6)
width = min(max_col_width, width)
column_letter = get_column_letter(xl_col_no)
worksheet.column_dimensions[column_letter].width = width
if np.issubdtype(dtyp, np.integer):
set_column_format(worksheet, column_letter, fmt_int)
if np.issubdtype(dtyp, np.floating):
set_column_format(worksheet, column_letter, fmt_float)
if file_exists and sheet_exists:
# move (append) rows from new worksheet to the `sheet_name` worksheet
wb = load_workbook(filename)
# retrieve generated worksheet name
new_sheet_name = set(wb.sheetnames) - set(sheet_names)
if new_sheet_name:
new_sheet_name = list(new_sheet_name)[0]
# copy rows written by `sf.to_excel(...)` to
copy_excel_cell_range(
src_ws=wb[new_sheet_name],
tgt_ws=wb[sheet_name],
tgt_min_row=startrow + 1,
with_style=True
)
# remove new (generated by Pandas) worksheet
del wb[new_sheet_name]
wb.save(filename)
wb.close()
Credit to Maxu for writing this function, and thanks to Deepspace for making me aware of this solution.

Pandas, Copy cells from workbook to another

I am having issues copying cells from excel workbook and pasting as values to another workbook.
I get an error on line rowSelected.append(sheet.cell(row = i, column = j).value) with the message AttributeError: 'str' object has no attribute 'cell'
Can anyone help with this?
import openpyxl
#Prepare the spreadsheets to copy from and paste too.
#File to be copied
wb = openpyxl.load_workbook(r"") #Add file name
sheet = wb["BusinessDetails"] #Add Sheet name
#File to be pasted into
template = openpyxl.load_workbook(r"") #Add file name
temp_sheet = template["Sheet1"] #Add Sheet name
#Copy range of cells as a nested list
#Takes: start cell, end cell, and sheet you want to copy from.
def copyRange(startCol, startRow, endCol, endRow, sheet):
rangeSelected = []
#Loops through selected Rows
for i in range(startRow,endRow + 1,1):
#Appends the row to a RowSelected list
rowSelected = []
for j in range(startCol,endCol+1,1):
rowSelected.append(sheet.cell(row = i, column = j).value)
#Adds the RowSelected List and nests inside the rangeSelected
rangeSelected.append(rowSelected)
return rangeSelected
#Paste range
#Paste data from copyRange into template sheet
def pasteRange(startCol, startRow, endCol, endRow, sheetReceiving,copiedData):
countRow = 0
for i in range(startRow,endRow+1,1):
countCol = 0
for j in range(startCol,endCol+1,1):
sheetReceiving.cell(row = i, column = j).value = copiedData[countRow][countCol]
countCol += 1
countRow += 1
def createData():
print("Processing...")
selectedRange = copyRange(1,2,4,14,sheet) #Change the 4 number values
pastingRange = pasteRange(1,3,4,15,temp_sheet,selectedRange) #Change the 4 number values
#You can save the template as another file to create a new file here too.s
template.save(r"")
print("Range copied and pasted!")
copyRange(2,4,30,78,"BusinessDetails")
pasteRange(2,4,30,78,"Sheet1")
It must be:
copyRange(2,4,30,78,sheet)
pasteRange(2,4,30,78,temp_sheet)
i.e. you need to pass the sheet objects, not the sheet names to your functions.
Update as per comment:
rangeSelected = copyRange(2,4,30,78,sheet)
pasteRange(2,4,30,78,temp_sheet, rangeSelected)

Excelsheet in xlsxwriter

I want to create a workbook and worksheet once using xlsxwriter outside my function, as I am calling my function from a robot framework to insert the items in excel.
However, my code gives me an error.
class writetoexcel:
workbook = xlsxwriter.Workbook('Example2.xlsx')
worksheet = workbook.add_worksheet()
def my_func(self, value, count):
print(value)
row = 0
column = 1
# worksheet.write_string(row, column, value)
for item in value:
worksheet.write_string(row, column, item)
worksheet.write_string(row, column, item)
row += 1
workbook.close()
You are getting an error because you are trying to initiate the xlsxwriter outside of the function or of the init method. This is your corrected code:
import xlsxwriter
class writetoexcel:
def my_func(self, value):
workbook = xlsxwriter.Workbook('Example2.xlsx')
worksheet = workbook.add_worksheet()
print(value)
row = 0
column = 1
for item in value:
worksheet.write_string(row, column, item)
row += 1
workbook.close()
Then you need to create an object:
myworkbook = writetoexcel()
And finally call its method we created:
myworkbook.my_func('abcd')
Output:
Finally i think this code is a better approach if you want to handle the workbooks as objects:
class writetoexcel:
def __init__(self):
self.workbook = xlsxwriter.Workbook('Example2.xlsx')
self.worksheet = self.workbook.add_worksheet()
def my_func(self, value):
row = 0
column = 1
for item in value:
self.worksheet.write_string(row, column, item)
row += 1
self.workbook.close()

isnull() and dropna() not working for pandas 0.22 when using xlwings to get dataframe

Desperate about this mystery. So i just upgraded my pandas to 0.22 (from 0.18) and mysteriously, when using xlwings, dropna or isnull does NOT work anymore. I see that myTemp is still giving me the correct True and False, yet
unwindDF will give me all the df_raw data just with everything filled to become nan and naT. Similar issue for noPx.
This is the case even if I manually assign np.nan to a cell Yet surprisingly, when in the same file I create a simple df towards the end, then myTest1
is working well. why? is there something special about xlwings with pandas 0.22?
My code is below and my xlsx file in the image.
import pythoncom
import pandas as pd
import xlwings as xw
import numpy as np
folder_path = 'S:/Order/all PNL files/'
excel_name='pnlTest.xlsx'
pnl_excel_path = folder_path + excel_name
sheetName = 'Sheet1'
pythoncom.CoInitialize()
app = None
bk = None
app_count = xw.apps.count
for i in range(app_count):
try:
app = xw.apps[i]
temp = app.books[excel_name]
bk = temp
print()
print("Using Opened File")
except:
print()
if bk == None:
print("Open New Excel App")
app = xw.App()
bk = xw.Book(pnl_excel_path)
bk.app.calculation = 'manual'
bk.app.screen_updating = False
sht = bk.sheets[sheetName]
last_row_index = sht.range('A1').end('down').row
df_raw = sht.range('A1:M' + str(last_row_index)).options(pd.DataFrame, header=1,
index=0).value
myTemp = df_raw['UNWD_DT'].isnull()
unwindDF = df_raw[df_raw['UNWD_DT'].isnull()]
df_raw.loc[10,'Curr_Px']=np.nan
df_raw.iloc[10,11]=np.nan
noPx=df_raw[df_raw['Curr_Px'].isnull()]
df = pd.DataFrame({'a':[0,0,1,1], 'b':[0,1,0,1],'c':[np.nan,1,0,np.nan]})
myTemp1=df['c'].isnull()
myTest1=df[df['c'].isnull()]
df_raw.dropna(thresh=2,inplace=True)
df_raw2=df_raw.dropna(thresh=2)