I have a qtablewidet that has data and when the user clicks the export button a dialog will appear asking for filename to save as excel, how do i do that using openpyxl?
here is my code
self.exportbtn.clicked.connect(self.export)
def export(self):
try:
filename = QtWidgets.QFileDialog.getSaveFileName(self, 'Save file', '','Excel files(*.xlsx)')
wb = Workbook()
sheet = wb.active
for column in range(self.tableWidget.columnCount()):
for row in range(self.tableWidget.rowCount()):
try:
text = str(self.tableWidget.item(row, column).text())
sheet.write(row, column, text)
wb.save(filename)
except Exception as e:
print("Error Writing file.")
except Exception as e:
print("Error Saving file.")
when i try to click save from the dialog, the output right now is this
how do i save the whole data including the headers from qtablewidget to an excel file using openpyxl?
update:
i edited my code now and i am able to create the file but the data from the qtablewidget is still not written in the excel file
def export(self):
filename, filter = QtWidgets.QFileDialog.getSaveFileName(self, 'Save file', '','Excel files (*.xlsx)')
wb = Workbook()
sheet = wb.active
if not filename:
for column in range(self.tableWidget.columnCount()):
for row in range(self.tableWidget.rowCount()):
try:
text = str(self.tableWidget.item(row, column).text())
sheet.write(row, column, text)
except AttributeError:
pass
wb.save(filename)
i tried printing the data from the qtablewidget and it shows, it just doesn't save in the excel file, is there still something missing?
So your line wb.save(filename) is inside your for loop, thereby the same filename is being saved on every loop.
Move that line outside and after the for loops at the outer indentation and therefore save it only once.
Also, ensure that the filename does not already exist, else you may get a pop dialog "Are you sure?" and you then need to force save it.
Almost all static methods of QFileDialog (except for getExistingDirectory() and getExistingDirectoryUrl()) return a tuple in the form of (file(s), filter).
For getOpenFileNames() (note the plural) the first object is a list of strings indicating the selected files, in the other cases it's the file path as a string or URL.
Do note that if the dialog is canceled, the file string (or the list) is empty, so you should check that before going on with the file writing:
filename, filter = QtWidgets.QFileDialog.getSaveFileName(
self, 'Save file', '','Excel files(*.xlsx)')
if not filename:
return
# ...
Also, you should not try to save the file at each cycle of the for loop.
While 99% of the functions in Qt behave in the same way in PyQt, that's not always true, especially for situations for which C++ uses referenced variables. Whenever you are not sure about a function or get unexpeted behavior from it, you can check the PyQt documentation (the returned type(s) are specified at the end of the function definition, after the →) or just call help(class.function) in the python consolle. An even simpler solution is to just print the returned value, and you'll see that for yourself.
def imag_Export_Report(self):
self.cur.execute('''SELECT name, phone, image FROM photo''')
rows = self.cur.fetchall()
excel_file = QtWidgets.QFileDialog.getSaveFileName(self, "save file",'./','Excel Files (*.xlsx)')
workbook = xlsxwriter.Workbook(excel_file[0])
sheet1 = workbook.add_worksheet()
sheet1.write(0, 0, 'name ')
sheet1.write(0, 1, ' phone')
sheet1.write(0, 2, 'image ')
row_number = 1
for row in rows:
column_number = 0
for item in row:
sheet1.write(row_number, column_number, str(item))
column_number += 1
row_number += 1
workbook.close()
self.con.commit()
Related
I am writing a GUI app that loads a csv file, cleans it and then saves it as a JSON file dump in same directory...I am stuck please help...I have created two buttons one to handle the loading of the file and another to write JSON, I know I can use one button to achieve this, but don't know how to save the file so it appears in the same directory as the csv file.
my program so far:
def load_frequency_data():
global df, df_rows
file_path = label_file['text']
try:
csv_filename = r'{}'.format(file_path)
df = pd.read_csv(csv_filename, delimiter=',')
df.rename(columns={'airport_ident': 'ident'}, inplace=True)
df = df[['ident', 'frequency_mhz']]
clear_frequency_data()
my_tree['columns'] = list(df.columns)
my_tree['show'] = 'headings'
for column in my_tree['columns']:
my_tree.heading(column, text=column)
df_rows = df.to_numpy().tolist()
for row in df_rows:
my_tree.insert('', 'end', values=row)
return None
except ValueError:
tkinter.messagebox.showerror('Information', 'File is invalid')
return None
except FileNotFoundError:
tkinter.messagebox.showerror('Information', "File not found")
my second button code:
def save_tojson():
if messagebox.askyesno('Confirmation', 'Are you sure you want to save data as json file?'):
data = df.to_json(orient='split', indent=3)
I am trying to use the converted csv file (df) to save as a JSON file.
You can specify the path_or_buf argument of pandas.DataFrame.to_json to determine the exported path:
from pathlib import Path
def save_tojson():
file_path = Path(label_file['text'])
if messagebox.askyesno('Confirmation', 'Are you sure you want to save data as json file?'):
df.to_json(file_path.with_suffix('.csv'), orient='split', indent=3)
All I want to do is copy a worksheet from an excel workbook to another excel workbook in Python.
I want to maintain all formatting (coloured cells, tables etc.)
I have a number of excel files and I want to copy the first sheet from all of them into one workbook. I also want to be able to update the main workbook if changes are made to any of the individual workbooks.
It's a code block that will run every few hours and update the master spreadsheet.
I've tried pandas, but it doesn't maintain formatting and tables.
I've tried openpyxl to no avail
I thought xlwings code below would work:
import xlwings as xw
wb = xw.Book('individual_files\\file1.xlsx')
sht = wb.sheets[0]
new_wb = xw.Book('Master Spreadsheet.xlsx')
new_wb.sheets["Sheet1"] = sht
But I just get the error:
----> 4 new_wb.sheets["Sheet1"] = sht
AttributeError: __setitem__
"file1.xlsx" above is an example first excel file.
"Master Spreadsheet.xlsx" is my master spreadsheet with all individual files.
In the end I did this:
def copyExcelSheet(sheetName):
read_from = load_workbook(item)
#open(destination, 'wb').write(open(source, 'rb').read())
read_sheet = read_from.active
write_to = load_workbook("Master file.xlsx")
write_sheet = write_to[sheetName]
for row in read_sheet.rows:
for cell in row:
new_cell = write_sheet.cell(row=cell.row, column=cell.column,
value= cell.value)
write_sheet.column_dimensions[get_column_letter(cell.column)].width = read_sheet.column_dimensions[get_column_letter(cell.column)].width
if cell.has_style:
new_cell.font = copy(cell.font)
new_cell.border = copy(cell.border)
new_cell.fill = copy(cell.fill)
new_cell.number_format = copy(cell.number_format)
new_cell.protection = copy(cell.protection)
new_cell.alignment = copy(cell.alignment)
write_sheet.merge_cells('C8:G8')
write_sheet.merge_cells('K8:P8')
write_sheet.merge_cells('R8:S8')
write_sheet.add_table(newTable("table1","C10:G76","TableStyleLight8"))
write_sheet.add_table(newTable("table2","K10:P59","TableStyleLight9"))
write_to.save('Master file.xlsx')
read_from.close
With this to check if the sheet already exists:
#checks if sheet already exists and updates sheet if it does.
def checkExists(sheetName):
book = load_workbook("Master file.xlsx") # open an Excel file and return a workbook
if sheetName in book.sheetnames:
print ("Removing sheet",sheetName)
del book[sheetName]
else:
print ("No sheet ",sheetName," found, will create sheet")
book.create_sheet(sheetName)
book.save('Master file.xlsx')
with this to create new tables:
def newTable(tableName,ref,styleName):
tableName = tableName + ''.join(random.choices(string.ascii_uppercase + string.digits + string.ascii_lowercase, k=15))
tab = Table(displayName=tableName, ref=ref)
# Add a default style with striped rows and banded columns
tab.tableStyleInfo = TableStyleInfo(name=styleName, showFirstColumn=False,showLastColumn=False, showRowStripes=True, showColumnStripes=True)
return tab
Adapted from this solution, but note that in my (limited) testing (and as observed in the other Q&A), this does not support the After parameter of the Copy method, only Before. If you try to use After, it creates a new workbook instead.
import xlwings as xw
wb = xw.Book('individual_files\\file1.xlsx')
sht = wb.sheets[0]
new_wb = xw.Book('Master Spreadsheet.xlsx')
# copy this sheet into the new_wb *before* Sheet1:
sht.api.Copy(Before=new_wb.sheets['Sheet1'].api)
# now, remove Sheet1 from new_wb
new_wb.sheets['Sheet1'].delete()
This can be done using pywin32 directly. The Before or After parameter needs to be provided (see the api docs), and the parameter needs to be a worksheet <object>, not simply a worksheet Name or index value. So, for example, to add it to the end of an existing workbook:
def copy_sheet_within_excel_file(excel_filename, sheet_name_or_number_to_copy):
excel_app = win32com_client.gencache.EnsureDispatch('Excel.Application')
wb = excel_app.Workbooks.Open(excel_filename)
wb.Worksheets[sheet_name_or_number_to_copy].Copy(After=wb.Worksheets[wb.Worksheets.Count])
new_ws = wb.ActiveSheet
return new_ws
As most of my code runs on end-user machines, I don't like to make assumptions whether Excel is open or not so my code determines if Excel is already open (see GetActiveObject), as in:
try:
excel_app = win32com_client.GetActiveObject('Excel.Application')
except com_error:
excel_app = win32com_client.gencache.EnsureDispatch('Excel.Application')
And then I also check to see if the workbook is already loaded (see Workbook.FullName). Iterate through the Application.Workbooks testing the FullName to see if the file is already open. If so, grab that wb as your wb handle.
You might find this helpful for digging around the available Excel APIs directly from pywin32:
def show_python_interface_modules():
os.startfile(os.path.dirname(win32com_client.gencache.GetModuleForProgID('Excel.Application').__file__))
So i have the same excel workbook in several different different folders i.e. for each hotel I have a file and in that file there's an excel workbook. Now, I need to go in each file and change the contents of the cell 'B2' in worksheet "Set Up" to the hotel name (which is referred to as hotelname in my code). I try to run the code below but it gives me the error "C:\Python34\python-3.4.4.amd64\lib\site-packages\openpyxl\reader\worksheet.py:319: UserWarning: Data Validation extension is not supported and will be removed" and it doesn't change anything in my excel files?
from openpyxl import load_workbook
log = 'G:\Data\Hotels\hotelnames.txt' ##text file with a list of the hotel names
file = open(log, 'r')
hotelnames = []
line = file.readlines()
for a in line:
hotelnames.append(a.rstrip('\n'))
for hotel in hotelnames:
wb = load_workbook("G:\\Data\\Hotels\\"+hotel+"\\"+hotel+" - Meetings\\"+hotel+"_Action_Log.xlsx", data_only = True)
ws = wb["Set Up"]
ws['B2'] = hotel ### I want this cell to to have that particular hotel name
wb.save
Your code should be calling the method wb.save, not just referencing it. Do that by adding some parentheses and pass the file name to save the file to:
wb.save(filename)
wb.save only references the save method, but does not call it.
Also processing of the input file can be greatly simplified by iterating directly over the file object:
import os.path
with open(log) as f:
file_spec = os.path.join(r"G:\Data\Hotels", '{0}', '{0} - Meetings', '{0}_Action_Log.xlsx'
for hotel in f:
hotel = hotel.rstrip('\n') # probably hotel.rstrip() is sufficient
wb = load_workbook(file_spec.format(hotel), data_only = True)
ws = wb["Set Up"]
ws['B2'] = hotel
wb.save(file_spec.format(hotel)) # careful, this overwrites the original file, it would be safer to save it to a new file.
When one opens Excel workbook with Excel COM object
app = gencache.EnsureDispatch("Excel.Application")
doc = app.Workbooks.Open(filepath)
all print areas are dropped, but they're accessible via VBA when the file is opened normally.
Localized versions of MS Excel ignore print areas and titles when accessed as a COM object, so one must explicitly specify PageSetup.PrintArea|PrintTitleColumns|PrintTitleRows for each worksheet if needed.
for sh in self.doc.Worksheets: #explicitly specify print areas and titles
for name in sh.Names:
if name.Name.endswith("!Print_Area"):
sh.PageSetup.PrintArea = name.RefersTo
elif name.Name.endswith("!Print_Titles"):
#protect comma symbol in sheet name
chunks = name.RefersTo.replace(sheet.Name, "[sheet_name]").split(",")
chunks = [i.replace("[sheet_name]", sheet.Name) for i in chunks]
if len(chunks) == 1:
try: sh.PageSetup.PrintTitleColumns = chunks[0]
except: sh.PageSetup.PrintTitleRows = chunks[0]
else: sh.PageSetup.PrintTitleColumns, sh.PageSetup.PrintTitleRows = chunks
Source: Excel -> PDF (ExportAsFixedFormat)
UPD: Support sheet names with commas
I am trying to write a matrix prepared with NumPy to an EXCEL file. I need to specify a range of cells in which the matrix must be written.
I need to write the matrix to cells A4:Z512 in sheet 4 of the EXCEL file.
Now, the standard EXCEL file has 3 sheets, so I need to first add a 4th sheet and then write the matrix to it.
Is there a way to do this in python 2.7? Is it possible to do this with pure NumPy or not?
I have not used NumPy, so I am not sure if you can manipulate excel files. But for working on excel files I recommend using the win32com library. Below is some code I have used in the past to make win32com API easier to use. Feel free to use the code yourself. Hope this helps!
import win32com.client as win32
excel = win32.gencache.EnsureDispatch('Excel.Application')
def openExcel(makeExcelVisible=True):
excel.Visible = makeExcelVisible
def closeExcel():
excel.Application.Quit()
class ExcelFile(object):
# opens up a workbook to work on, not selecting a file name creates a new one
def __init__(self, fileName=None):
if fileName == None:
self.wb = excel.Workbooks.Add()
else:
self.wb = excel.Workbooks.Open(fileName)
self.ws = None
def addWorksheet(self):
# adds a new worksheet to the workbook and makes it the current worksheet
self.ws = self.wb.Worksheets.Add()
def selectWorksheet(self, worksheetName):
# selects a worksheet to work on
self.ws = self.wb.Worksheets(worksheetName)
def renameWorksheet(self, worksheetName):
# renames current worksheet
self.ws.Name = worksheetName
def save(self):
# saves the workbook
self.wb.Save()
def saveAs(self, fileName):
# saves the workbook with the file name
self.wb.SaveAs(fileName)
def close(self):
# closes the workbook
self.wb.Close()
def insertIntoCell(self, cellRow, cellCol, data):
self.ws.Cells(cellRow,cellCol).Value = data
def clearCell(self, cellRow, cellCol):
self.ws.Cells(cellRow,cellCol).Value = None
Here is an example of how to use the code above. It creates a new excel file, renames the worksheets, adds information into the first cell on each worksheet and saves the file as "test.xlsx". Default save location is your home directory.
worksheets = ["Servers", "Printers", "Drives", "IT Phones"]
information = ["Server WS", "Printer WS", "Driver WS", "IT Phone WS"]
def changeCells(information):
excelFile = ExcelFile()
for index in xrange(len(worksheets)):
sheetNumber = index + 1
if sheetNumber == 4:
excelFile.addWorksheet()
excelFile.selectWorksheet("Sheet%d" % sheetNumber)
excelFile.renameWorksheet(worksheets[index])
excelFile.insertIntoCell(1,1,information[index])
excelFile.saveAs("test.xlsx")
excelFile.close()
openExcel()
changeCells(information)
closeExcel()
Also, I would recommend looking at the API for win32com yourself. It's a very nice and useful library.
I put together the actual code you would need for entering your matrix on Sheet4 to A4:Z512.
def addMatrix(matrix):
# use ExcelFile("fileName.xlsx") if you need to add to a specific file
excelFile = ExcelFile()
excelFile.addWorksheet()
# default excel files only have 3 sheets so had to add one
excelFile.selectWorksheet("Sheet4")
# xrange(4,513) since end index is exclusive
for row in xrange(4,513):
# 1 for A, 26 for Z
for col in xrange(1,27):
mRow = row - 4
mCol = col - 1
excelFile.insertIntoCell(row, col, matrix[mRow][mCol])
excelFile.saveAs("test.xlsx")
excelFile.close()
matrix = list()
for row in xrange(509):
matrix.append([])
for col in xrange(26):
matrix[row].append(0)
# the matrix is now filled with zeros
# use openExcel(False) to run faster, it won't open a window while running
openExcel()
addMatrix(matrix)
closeExcel()