Pandas add data to different sheets xlsxwriter - python

Hello I have data in list of dicts. I'm using panda DataFrame to parse from dict to excel. Data are fetch 5 different places. I would like to add data into different spreadsheet.
Here is the code I'm trying, but it doesn't add new sheets, it overwrites
def write_xlsx(filename, sheetname, data):
workbook = xlsxwriter.Workbook(filename)
checksheet = workbook.get_worksheet_by_name(sheetname)
if checksheet is None:
worksheet = workbook.add_worksheet(sheetname)
# Store the worksheet objects in a dict indexed by name.
my_worksheets = {}
for worksheet in workbook.worksheets():
my_worksheets[worksheet.get_name()] = worksheet
df = pd.DataFrame(data)
# Create a Pandas Excel writer using XlsxWriter as the engine.
writer = pd.ExcelWriter(filename, engine='xlsxwriter')
df.to_excel(writer, sheet_name=sheetname, index=False, startrow=1, header=False)
# Set the column widths
workbook = writer.book
worksheet = writer.sheets[sheetname]
header_format = workbook.add_format({'text_wrap': True})
columns_format = workbook.add_format({'text_wrap': True})
# Write the column headers with the defined format.
for col_num, value in enumerate(df.columns.values):
worksheet.write(0, col_num + 0, value, header_format)
writer.save()

Related

Python - Excel adding custom column headings

I am using the Coinmarketcap REST Api for having the latest cryptocurrency categories.
The code prints the JSON response into a DataFrame which is used for the transfer to excel (df.to_excel). Im using the "for column in df" for a bigger width in excel.
Now I would like to know how I can add costum column headings into the excel sheet.
def Cryptocurrencies():
url = 'https://pro-api.coinmarketcap.com/v1/cryptocurrency/categories'
parameters = {
}
headers = {
'Accept': 'application/json',
'X-CMC_PRO_API_KEY': 'mypersonalapikey',
}
session = Session()
session.headers.update(headers)
data = session.get(url, params=parameters)
response = session.get(url, params=parameters)
f = (json.loads(response.text)['data'])
df = pd.DataFrame(f)
writer = pd.ExcelWriter("Workingpaper1D.xlsx",
engine='xlsxwriter',
datetime_format='mmm d yyyy hh:mm:ss',
date_format='mmmm dd yyyy')
df.to_excel(writer, sheet_name='Sheet1',
startrow=1, header=False, index=False, )
(max_row, max_col) = df.shape
worksheet = writer.sheets['Sheet1']
worksheet.autofilter(0, 0, max_row, max_col - 1)
for column in df:
column_length = max(df[column].astype(str).map(len).max(), len(column))
col_idx = df.columns.get_loc(column)
writer.sheets['Sheet1'].set_column(col_idx, col_idx, column_length)
writer.save()
print(df)
return
You can set a custom header like this:
# Convert the dataframe to an XlsxWriter Excel object. Note that we turn off
# the default header and skip one row to allow us to insert a user defined
# header.
df.to_excel(writer, sheet_name='Sheet1', startrow=1, header=False)
# Get the xlsxwriter workbook and worksheet objects.
workbook = writer.book
worksheet = writer.sheets['Sheet1']
# Add a header format.
header_format = workbook.add_format({
'bold': True,
'text_wrap': True,
'valign': 'top',
'fg_color': '#D7E4BC',
'border': 1})
# Write the column headers with the defined format.
for col_num, value in enumerate(df.columns.values):
worksheet.write(0, col_num + 1, value, header_format)
See also this section of the XlsxWriter docs on Formatting of the Dataframe headers.

ValueError: Sheet 'Sheet1' already exists and if_sheet_exists is set to 'error'

I am trying to create an excel file of 3 columns: System Date, Time, Value on a webpage at that time.
Intention is to create a dataframe of the 3 values, every time the code runs, and append the dataframe to existing excel workbook (with one existing sheet).
I am able to create dataframe every time code runs, but when I try to append it to an excel file, it throws error:
ValueError: Sheet 'Sheet1' already exists and if_sheet_exists is set to 'error'
Can you please suggest, where am I going wrong.
# Importing Libraries
from datetime import datetime
import pandas as pd
import requests
from bs4 import BeautifulSoup
import openpyxl
#getting today's date amd formatting it
now = datetime.now()
Date = now.strftime ("%d/%m/%Y")
Time = now.strftime ("%H:%M")
# GET request to scrape. 'Page' variable to assign contents
page = requests.get("https://www.traderscockpit.com/?pageView=live-nse-advance-decline-ratio-chart")
# Create BeautifulSoup object to parse content
soup = BeautifulSoup(page.content, 'html.parser')
adv = soup.select_one('a:-soup-contains("Advanced:")').next_sibling.strip()
dec = soup.select_one('a:-soup-contains("Declined:")').next_sibling.strip()
ADratio = round(int(adv)/int(dec), 2)
df = pd.DataFrame({tuple([Date, Time, ADratio])})
#Load workbook and read last used row
path = r'C:\Users\kashk\OneDrive\Documents\ADratios.xlsx'
writer = pd.ExcelWriter (path, engine='openpyxl', mode = 'a')
wb = openpyxl.load_workbook(path)
startrow = writer.sheets['Sheet1'].max_row
#Append data frame to existing table in existing sheet
df.to_excel (writer, sheet_name = 'Sheet1', index = False, header = False, startrow = startrow)
writer.save()
writer.close()
A fast and easy solution would be upgrading your pandas > 1.4.0 since it provides a if_sheet_exists = 'overlay' Source
pd.ExcelWriter(path, engine='openpyxl', mode='a', if_sheet_exists='overlay')
If you don't want to upgrade your pandas, there is a way to work around by removing and re-write the sheet into the excel file. (Not recommended if you have a lot of records since it will be slow).
path, sheet_name = 'ADratios.xlsx' , 'Sheet 1'
df.columns = ['Date','Time','ADratio']
with pd.ExcelWriter(path, engine='openpyxl', mode='a', if_sheet_exists='replace') as writer:
book = openpyxl.load_workbook(path, 'r')
df_bak = pd.read_excel(path)
writer.book = openpyxl.load_workbook(path)
writer.book.remove(writer.book.worksheets[writer.book.sheetnames.index(sheet_name)])
writer.sheets = {ws.title:ws for ws in writer.book.worksheets}
pd.concat([df_bak, df], axis=0).to_excel(writer, sheet_name=sheet_name, index = False)

writing data to the same file from different functions

Currently I can write results from within each function to an individual file.
How would I write the results from the 2 functions to the same file?
I think I would need to pull out writer = pd.ExcelWriter('All Results', engine='xlsxwriter') with new file name outside of the function but I dont know how to handle the writing of each df_Final...
Input:
ExcelName='....'
t1=pd.read_excel('.....')
t2=['.......']
def F1(Input_Data):
writer = pd.ExcelWriter('F1_Results', engine='xlsxwriter')
.
.
.
df_Final.to_excel(writer, sheet_name=writeto[3],index=False, header=False)
writer.save()
return
def F2(Input_Data):
writer = pd.ExcelWriter('F2_Results', engine='xlsxwriter')
.
.
.
df_Final.to_excel(writer, sheet_name=writeto[7],index=False, header=False)
writer.save()
return
Solution:
This helper function might help you out:
def append_df_to_excel(filename, df, sheet_name='Sheet1', startrow=None,
truncate_sheet=False,
**to_excel_kwargs):
"""
Append a DataFrame [df] to existing Excel file [filename]
into [sheet_name] Sheet.
If [filename] doesn't exist, then this function will create it.
Parameters:
filename : File path or existing ExcelWriter
(Example: '/path/to/file.xlsx')
df : dataframe to save to workbook
sheet_name : Name of sheet which will contain DataFrame.
(default: 'Sheet1')
startrow : upper left cell row to dump data frame.
Per default (startrow=None) calculate the last row
in the existing DF and write to the next row...
truncate_sheet : truncate (remove and recreate) [sheet_name]
before writing DataFrame to Excel file
to_excel_kwargs : arguments which will be passed to `DataFrame.to_excel()`
[can be dictionary]
Returns: None
"""
from openpyxl import load_workbook
# ignore [engine] parameter if it was passed
if 'engine' in to_excel_kwargs:
to_excel_kwargs.pop('engine')
writer = pd.ExcelWriter(filename, engine='openpyxl')
# Python 2.x: define [FileNotFoundError] exception if it doesn't exist
try:
FileNotFoundError
except NameError:
FileNotFoundError = IOError
try:
# try to open an existing workbook
writer.book = load_workbook(filename)
# get the last row in the existing Excel sheet
# if it was not specified explicitly
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 = {ws.title:ws for ws in writer.book.worksheets}
except FileNotFoundError:
# file does not exist yet, we will create it
pass
if startrow is None:
startrow = 0
# write out the new sheet
df.to_excel(writer, sheet_name, startrow=startrow, **to_excel_kwargs)
# save the workbook
writer.save()
NOTE: for Pandas < 0.21.0, replace sheet_name with sheetname!
Usage examples:
append_df_to_excel('/home/data/test.xlsx', df)
append_df_to_excel('/home/data/test.xlsx', df, header=None, index=False)
append_df_to_excel('/home/data/test.xlsx', df, sheet_name='Sheet2', index=False)
append_df_to_excel('/home/data/test.xlsx', df, sheet_name='Sheet2', index=False, startrow=25)
You can modify the function to receive filename as a parameter
def write_to_excel(filename, input_data):
writer = pd.ExcelWriter(filename, engine='xlsxwriter')
.
.
.
df_Final.to_excel(writer, sheet_name=writeto[3],index=False, header=False)
writer.save()
return
#Then use like
write_to_excel("F2_Results", input_data)

Create Excel Tables from Dictionary of Dataframes

I have dictionary of dataframes.
dd = {
'table': pd.DataFrame({'Name':['Banana'], 'color':['Yellow'], 'type':'Fruit'}),
'another_table':pd.DataFrame({'city':['Atlanta'],'state':['Georgia'], 'Country':['United States']}),
'and_another_table':pd.DataFrame({'firstname':['John'], 'middlename':['Patrick'], 'lastnme':['Snow']}),
}
I would like to create an Excel file which contains Excel Table objects created from these dataframes. Each Table needs to be on a separate Tab/Sheet and Table names should match dataframe names.
Is this possible to do with Python?
So far I was only able to export data to Excel normally without converting to tables using xlsxwriter
writer = pd.ExcelWriter('Results.xlsx', engine='xlsxwriter')
for sheet, frame in dd.items():
frame.to_excel(writer, sheet_name = sheet)
writer.save()
For writing multiple sheets from Pandas, use the openpyxl library. In addition, to prevent overwriting, set the workbook sheets before each update.
Try this code:
import pandas as pd
import openpyxl
dd = {
'table': pd.DataFrame({'Name':['Banana'], 'color':['Yellow'], 'type':'Fruit'}),
'another_table':pd.DataFrame({'city':['Atlanta'],'state':['Georgia'], 'Country':['United States']}),
'and_another_table':pd.DataFrame({'firstname':['John'], 'middlename':['Patrick'], 'lastnme':['Snow']}),
}
filename = 'Results.xlsx' # must exist
wb = openpyxl.load_workbook(filename)
writer = pd.ExcelWriter(filename, engine='openpyxl')
for sheet, frame in dd.items():
writer.sheets = dict((ws.title, ws) for ws in wb.worksheets) # need this to prevent overwrite
frame.to_excel(writer, index=False, sheet_name = sheet)
writer.save()
# convert data to tables
wb = openpyxl.load_workbook(filename)
for ws in wb.worksheets:
mxrow = ws.max_row
mxcol = ws.max_column
tab = openpyxl.worksheet.table.Table(displayName=ws.title, ref="A1:" + ws.cell(mxrow,mxcol).coordinate)
ws.add_table(tab)
wb.save(filename)
Output

xlsxwriter intersect row and column formats

I'm saving pandas DataFrame to Excel with xlsxwriter. First I'm adding some format to columns (change font, for instance). Then I want to change background color for some rows. But when I add set_row function, all my column's format is gone. Is there a way to combine it?
import pandas as pd
data = pd.DataFrame({'test_data': [1,2,3,4,5]})
writer = pd.ExcelWriter('test.xlsx', engine='xlsxwriter')
pd.core.format.header_style = None
data.to_excel(writer, sheet_name='test', index=False)
workbook = writer.book
worksheet = writer.sheets['test']
font_fmt = workbook.add_format({'font_name': 'Arial', 'font_size': 10})
worksheet.set_column('A:A', None, font_fmt)
zebra = workbook.add_format({'bg_color': 'green'})
for index in range(5):
if index % 2 == 0:
worksheet.set_row(index+1, None, zebra)
writer.save()
This shall help:
import pandas as pd
data = pd.DataFrame({'test_data': [1,2,3,4,5]})
writer = pd.ExcelWriter('test.xlsx', engine='xlsxwriter')
pd.core.format.header_style = None
data.to_excel(writer, sheet_name='test', index=False)
workbook = writer.book
worksheet = writer.sheets['test']
formatdict = {'font_name': 'Calibri', 'font_size': 10, 'font_color':'red'}
font_fmt = workbook.add_format(formatdict)
worksheet.set_column('A:A', None, font_fmt)
zebra = workbook.add_format(formatdict)
zebra.set_bg_color('green')
for index in range(1,6,2):
worksheet.set_row(index, None, zebra)
writer.save()
Shall produce the following output:

Categories