argument of type 'builtin_function_or_method' is not iterable while using openpyxl to add-chart - openpyxl

I am trying to add a chart on multiple sheets in a XLSX file:
import openpyxl
from openpyxl import Workbook
from openpyxl import load_workbook
from openpyxl.chart import BarChart, Series, Reference
import glob
import os
def chartgen(filename):
wbook = openpyxl.load_workbook(filename)
sheets= wbook.sheetnames
for i in sheets:
chart1 = BarChart()
chart1.type = "col"
chart1.grouping = "stacked"
chart1.overlap = 100
chart1.style = 10
chart1.title = 'Chart'
chart1.y_axis.title = 'Y_Axis'
#chart1.x_axis.title = 'X_Axis'
data = Reference(datasheet, min_col=2, min_row=2, max_row=6, max_col=7) #--y_axis
cats = Reference(datasheet, min_col=1, min_row=2, max_row=6) #--x_axis
chart1.add_data(data, titles_from_data=True)
chart1.set_categories(cats)
chart1.legend = None
i.add_chart(chart1, "B3")
wbook.save(filename)
filenames = glob.glob('test/test.xlsx')
for filename in filenames:
chartgen(filename)
But I always got
Traceback (most recent call last): File "chart.py", line 36, in
chartgen(filename) File "chart.py", line 26, in chartgen
chart1.add_data(data, titles_from_data=True) File "/usr/local/lib/python3.7/site-packages/openpyxl/chart/_chart.py",
line 168, in add_data
range_string = u"{0}!{1}:{2}".format(data.sheetname, v[0], v[-1]) File
"/usr/local/lib/python3.7/site-packages/openpyxl/chart/reference.py",
line 132, in sheetname
return quote_sheetname(self.worksheet.title) File "/usr/local/lib/python3.7/site-packages/openpyxl/utils/cell.py", line
221, in quote_sheetname
if "'" in sheetname:
I also tried to create a new tab named chart after each data tab:
wbook = openpyxl.load_workbook(filename)
sheets= wbook.sheetnames
for i in sheets:
try:
reportsheet=wbook['chart']
except KeyError:
print(str('Creating chart from data, sheet name: ' + i + '_chart'))
wbook.create_sheet('chart')
reportsheet=wbook['chart']
This failed too. Due to duplicate chart tab name as chart?
Thanks!

Related

Storing string to clipboard

Hello I am trying to make an automation where I can iterate through the rows in a df column and copy and paste them one at a time to excel. I would like to include a loop to where I can press enter and it will copy the next cell. I have this code written for reference but it is not working.
import pandas as pd
import openpyxl
import pyperclip as pc
import pyautogui as pg
Excel_File = r'/Users/martinflores/Desktop/Control.xlsx'
df = pd.read_excel(Excel_File)
x= df['Age']
y = df['Name']
z = df['Count']
def main():
for index, row in df.iterrows():
string = row['Age']
cp = pc.copy(string)
return cp
pg.sleep(3)
pc.paste(main())
pg.press('down')
I thought my main function would save the string to the Clipboard and I could either paste by pg.hotkey('ctrl','v',) or pc.paste(main()) but it won't do anything.Also I am not sure if it matter but I am developing this code on IOS at the moment.

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.

How to wait 30 second after 20 requests selenium scraping

Hello i have a csv file 300 datas.
After 10 requests , the website stop to give me results.
How to pause 3 minutes my script after 10 requests
thanks you
my code :
societelist =[]
import csv
with open('1.csv') as csvfile:
reader = csv.reader(csvfile)
for row in reader:
browser = webdriver.Firefox(options=options)
browser.get("myurl".format(row[0]))
time.sleep(20)
try:
societe = browser.find_element_by_xpath('/html/body/div[3]/div[2]/div/div[1]/div[2]/div[1]/span[2]').text
except NoSuchElementException:
societe = 'Element not found'
societelist.append(societe)
print (row[0])
browser.quit()
df = pd.DataFrame(list(zip(societelist)), columns=['societe'])
data = df.to_csv('X7878.csv', index=False)
Use:
import csv
societelist =[]
with open('1.csv') as csvfile:
reader = csv.reader(csvfile)
for i, row in enumerate(reader): # i gives the index of the row.
browser = webdriver.Firefox(options=options)
browser.get("myurl".format(row[0]))
time.sleep(20)
try:
societe = browser.find_element_by_xpath('/html/body/div[3]/div[2]/div/div[1]/div[2]/div[1]/span[2]').text
except NoSuchElementException:
societe = 'Element not found'
societelist.append(societe)
print(row[0])
browser.quit()
if not ((i+1) % 10):
time.sleep(180)
df = pd.DataFrame(list(zip(societelist)), columns=['societe'])
df.to_csv('X7878.csv', index=False)
Alternate solution to write each line of text to Excel after scraping instead of writing all text at once.
import csv
import win32com.client as win32
# Launch excel
excel = win32.Dispatch('Excel.Application')
excel.Visible = 1
wb = excel.Workbooks.Add()
ws = wb.Sheets(1)
# Read csv and scrape webpage
with open('1.csv') as csvfile:
reader = csv.reader(csvfile)
for i, row in enumerate(reader): # i gives the index of the row.
browser = webdriver.Firefox(options=options)
browser.get("myurl".format(row[0]))
time.sleep(20)
try:
societe = browser.find_element_by_xpath('/html/body/div[3]/div[2]/div/div[1]/div[2]/div[1]/span[2]').text
except NoSuchElementException:
societe = 'Element not found'
# it may make sense to write the input text and the scraped value side by side.
ws.Cells(i+1, 1).Value = row[0]
ws.Cells(i+1, 2).Value = societe
print(row[0], societe)
browser.quit()
if not ((i+1) % 10):
time.sleep(180)
# If you want to save the file programmatically and close excel.
path = r'C:\Users\jarodfrance\Documents\X7878.xlsx'
wb.SaveAs(path)
wb.Close()
excel.Quit()

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

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'

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)