Insert column using openpyxl - python

I'm working on a script that modifies an existing excel document and I need to have the ability to insert a column between two other columns like the VBA macro command .EntireColumn.Insert.
Is there any method with openpyxl to insert a column like this?
If not, any advice on writing one?

Here is an example of a much much faster way:
import openpyxl
wb = openpyxl.load_workbook(filename)
sheet = wb.worksheets[0]
# this statement inserts a column before column 2
sheet.insert_cols(2)
wb.save("filename.xlsx")

Haven't found anything like .EntireColumn.Insert in openpyxl.
First thought coming into my mind is to insert column manually by modifying _cells on a worksheet. I don't think it's the best way to insert column but it works:
from openpyxl.workbook import Workbook
from openpyxl.cell import get_column_letter, Cell, column_index_from_string, coordinate_from_string
wb = Workbook()
dest_filename = r'empty_book.xlsx'
ws = wb.worksheets[0]
ws.title = "range names"
# inserting sample data
for col_idx in xrange(1, 10):
col = get_column_letter(col_idx)
for row in xrange(1, 10):
ws.cell('%s%s' % (col, row)).value = '%s%s' % (col, row)
# inserting column between 4 and 5
column_index = 5
new_cells = {}
ws.column_dimensions = {}
for coordinate, cell in ws._cells.iteritems():
column_letter, row = coordinate_from_string(coordinate)
column = column_index_from_string(column_letter)
# shifting columns
if column >= column_index:
column += 1
column_letter = get_column_letter(column)
coordinate = '%s%s' % (column_letter, row)
# it's important to create new Cell object
new_cells[coordinate] = Cell(ws, column_letter, row, cell.value)
ws._cells = new_cells
wb.save(filename=dest_filename)
I understand that this solution is very ugly but I hope it'll help you to think in a right direction.

Related

Openpyxl - Copy range of cells(with formula) from a workbook to another

I'm trying to copy specific rows from Workbook 1 and append it to the existing data in Workbook 2.
Copy the highlighed rows from
Workbook 1,
and append them in Workbook 2 below 'March'
So far I succeeded to copy and paste the range, but there are two problems:
1.Cells are a shifted
2.The percentage(formula) is missing, leaving only numeric values.
See Result here
import openpyxl as xl
source = r"C:\Users\Desktop\Test_project_20200401.xlsx"
wbs = xl.load_workbook(source)
wbs_sheet = wbs["P2"] #selecting the sheet
destination = r"C:\Users\Desktop\Try999.xlsx"
wbd = xl.load_workbook(destination)
wbd_sheet = wbd["A3"] #select the sheet
row_data = 0
for row in wbs_sheet.iter_rows():
for cell in row:
if cell.value == "Yes":
row_data += cell.row
for row in wbs_sheet.iter_rows(min_row=row_data, min_col = 1, max_col=250, max_row = row_data+1):
wbd_sheet.append((cell.value for cell in row))
wbd.save(destination)
Does anyone have any idea on how can I solve this?
Any feedback/solution would help!
Thanks!
I think min_col should = 0
Range("A1").Formula (in VBA) gets the formula.
Range("A1").Value (in VBA) gets the value.
So try using .formula in Python
(thanks to: Get back a formula from a cell - VBA ... if this works)
Just want to add my own solution in here.
What I did, was to iterate through the columns and apply "cell.number_format = '0%', which converts your cell value to percentage.
for col in ws.iter_cols(min_row=1, min_col=2, max_row=250, max_col=250):
for cell in col:
cell.number_format = '0%'
More info can be found in here:
https://openpyxl.readthedocs.io/en/stable/_modules/openpyxl/styles/numbers.html

Python Openpyxl iter_rows and add defined value in each cell

Question: Can someone please let me know how I can achieve the following task:
I've defined the column, but i need a specific value to go into each cell within that column.
Also, if column 6 only has x amount of rows, then i want column 7 to also have only x amount of rows with the values pasted in it.
This is the code i've tried.
import openpyxl
wb = openpyxl.load_workbook(filename=r'C:\Users\.spyder-py3\data\BMA.xlsx')
ws = wb.worksheets[0]
for row in ws.iter_rows('G{}:G{}'.format(ws.min_row,ws.max_row)):
for cell in row:
ws.cell(row=cell, column=7).value = 'BMA'
wb.save(r'C:\Users\.spyder-py3\data\BMA.csv')
wb.close()
I figured out most of the issue by looking at this answer:
https://stackoverflow.com/a/15004956/9649146
This is the code i end up with:
import openpyxl
wb = openpyxl.load_workbook(filename=r'C:\Users\.spyder-py3\data\AAXN.xlsx')
ws = wb.worksheets[0]
r = 2
for row in ws.iter_rows('G{}:G{}'.format(ws.min_row,ws.max_row)):
for cell in row:
ws.cell(row=r, column=7).value = 'AAXN'
r += 1
wb.save(r'C:\Users\.spyder-py3\data\AAXN.csv')
wb.close()
Or, you can do something like this:
for row in filesheet.iter_rows(min_row=2, max_row=file_sheet.max_row):
filesheet.cell(row=row[0].row, column=7).value = 'my value'

openpyxl paste collected list in specific range?

First: I just started with python. And spefically with openpyxl.
So I went ahead and tried this code out:
from openpyxl import load_workbook
wb = load_workbook('E:/Python36/Test/sample.xlsx')
ws = wb['Sheet']
#get all values, without knowing the row and column dimension - possible?
myRange = []
for row in ws.iter_rows(min_row=9, max_row=13, min_col=9, max_col=11):
rowList = []
for cell in row:
rowList.append(cell.value)
myRange.append(rowList)
targetRange = ws.iter_rows()
#paste all values, in specific range on new sheet or new wb? how?
wb.create_sheet('Sheet2')
ws = wb['Sheet2']
for i, j in zip(targetRange, myRange):
for a, b in zip(i, j):
a.value = b
wb.save('E:/Python36/Test/exa.xlsx')
And now I'm stuck :)
My questions are:
1) I can't figure out how to get all cell values on a sheet, without knowing the row and column dimensions on fore hand - is this possible?
2) I want to paste all the found values (range) in a (other) specific workbook sheet beginning in row 4 column 4.
TiA!

xlsx writing cell_value error, writing to new worksheet

I'm trying to build a report generator which reads excel sheets and returns rows which contain values. I built a version which works as I require but only works for csv this is only my 1st code-mash-together, but it worked. I now would like to include conditional formatting as well (highlight certain cells values eg. if <65 format red) and so that required that I rewrite with xlsx sheets rather than csv.
Below is my attempt at getting this to work...
I can find the values and return the row, but on the second run through it returns an error
AttributeError: 'Worksheet' object has no attribute 'cell_value'
Which is surprising because it worked just previously and stepping through the code retuns the values I want.... I have tried changing it to .value, but returns:
AttributeError: 'function' object has no attribute 'value'
Help, I have no idea what I'm doing now. If it doens't make any sense i'm happy to post my original code for the csv to 'explain'
Thanks
import xlsxwriter
import xlrd
import os
import xlwt
# open original excelbook and access first sheet
for excelDocs in os.listdir('.'):
if not excelDocs.endswith('.xlsx'):
continue # skip non-xlsx files
workbook = xlrd.open_workbook(excelDocs)
sheet = workbook.sheet_by_index(0)
cellslist = []
i = 0
#########WORKS!#####################
for row in range(sheet.nrows):
for col in range(sheet.ncols):
if sheet.cell_value(row, col) == 'CP' or sheet.cell_value(row, col) == 'LNA' or sheet.cell_value(row, col) == 'Last Name':
i = i + 1
data = [sheet.cell_value(0, col) for col in range(sheet.ncols)]
workbook = xlsxwriter.Workbook()
sheet = workbook.add_worksheet('excelDocs')
for index, value in enumerate(data):
sheet.write(i, index, value)
workbook = xlrd.open_workbook(excelDocs)
I have no experience with xlsxwriter, xlrd or xlwt. As this is your "1st code-mash-together" I figured I would offer an alternative using openpyxl.
I do not have your data, so testing is a little difficult, but any syntax errors could be fixed. Please let me know if this does not run and I will help fix if required.
I am assuming your output is to a seperate file(report.xlsx here) and a tab for each workbook checked(each tab named for source book name).
import openpyxl
from openpyxl import *
from openpyxl.utils import get_column_letter
interestingValues = ['CP','LNA', 'LastName']
report = Workbook()
dest_filename = 'report.xlsx'
# open original excelbook and access first sheet
for excelDocs in os.listdir('.'):
if not excelDocs.endswith('.xlsx'):
continue # skip non-xlsx files
workbook = load_workbook(excelDocs)
sheet = workbook.active
workingReportSheet = report.create_sheet(str(excelDocs.split('.')[0]))
i = 0
for row in range(1,sheet.max_row):
for col in range(sheet.max_column):
columnLetter = get_column_letter(col +1)
if str(sheet['%s%s' % (columnLetter,row)].value) in interestingValues:
i += 1
data = [sheet['%s%s' % (str(get_column_letter(col)),i)].value for col in range(1,sheet.max_column +1)]
for index, value in enumerate(data):
workingReportSheet['%s%s' % (str(get_column_letter(index+1)),i)].value = value
report.save(filename = dest_filename)
Reading your code again, it may be that you are discarding your output.
Try the below.
import xlsxwriter
import xlrd
import os
import xlwt
#Create output sheet
outputworkbook = xlsxwriter.Workbook()
# open original excelbook and access first sheet
for excelDocs in os.listdir('.'):
if not excelDocs.endswith('.xlsx'):
continue # skip non-xlsx files
workbook = xlrd.open_workbook(excelDocs)
sheet = workbook.sheet_by_index(0)
cellslist = []
i = 0
outputsheet = outputworkbook.add_worksheet('excelDocs')
for row in range(sheet.nrows):
for col in range(sheet.ncols):
if sheet.cell_value(row, col) == 'CP' or sheet.cell_value(row, col) == 'LNA' or sheet.cell_value(row, col) == 'Last Name':
i = i + 1
data = [sheet.cell_value(0, col) for col in range(sheet.ncols)]
for index, value in enumerate(data):
outputsheet.write(i, index, value)

How to transfer data from one worksheet into another using python in the same workbook?

I want to transfer my data which is in 'Sheet1' into worksheet 'Sheet2'in the same workbook, using python.I have written the script below, but facing an 'IndexError: list index out of range'. I know this is not the best way to go about it. I will appreciate if anyone can guide me with a more efficient way to go about it. I am sharing the Snapshot of excel file below
Can I directly enter 'Sheet1' cell value ---> 'Sheet2' cell value rather than doing 'Sheet1' cell value ---> List---->'Sheet2' cell value?
import openpyxl
wb = openpyxl.load_workbook('C:\Users\laban\Desktop\Par-emails1.xlsx')
type(wb)
wb.get_sheet_names()
sheet = wb.get_sheet_by_name('Sheet1')
type(sheet)
anotherSheet = wb.active
sheet1 = wb.get_sheet_by_name('Sheet2')
type(sheet1)
par=[sheet.cell(row= col, column=1).value for col in range(1, 2450)]
email_no=[sheet.cell(row= col, column=2).value for col in range(1, 2450)]
Domain=[sheet.cell(row= col, column=3).value for col in range(1, 2450)]
email=[sheet.cell(row= col, column=4).value for col in range(1, 2450)]
for x in range(0,2450):
if email_no[x]<9:
sheet1.cell(row= x+1, column=1).value=par[x]
sheet1.cell(row= x+1, column=2).value=email_no[x]
sheet1.cell(row= x+1, column=3).value=Domain[x]
sheet1.cell(row= x+1, column=4).value=email[x]
wb.save('C:\Users\laban\Desktop\Par-emails1.xlsx')
You can use:
wb = openpyxl.load_workbook('C:/Users/laban/Desktop/Par-emails1.xlsx')
sheet1 = wb.get_sheet_by_name('Sheet1')
sheet2 = wb.get_sheet_by_name('Sheet2')
for i,row in enumerate(sheet1.iter_rows()):
for j,col in enumerate(row):
sheet2.cell(row=i+1,column=j+1).value = col.value
Apparently in 2.4 you can do this with one command: Copy whole worksheet with openpyxl
Obviously this is very simplified version from what I am currently using.
Here is a code snippet to copy data from sheet1 to sheet2 without any formatting.
You dont need to specify max rows , max columns as you can get it using
sheet.max_row and sheet.max_columns methods.
from openpyxl.cell import Cell
max_row = sheet1.max_row #Get max row of first sheet
max_col = sheet1.max_column #Get max column of first sheet
for row_num in range(1,max_row + 1): #Iterate through rows
for col_num in range(1, max_col + 1): #Iterate through columns
_cell1 = sheet1.cell(row=row_num, column=col_num)
_cell2 = sheet2.cell(row=row_num, column=col_num)
_cell2.value = _cell1.value
Added extra variables for understanding. You can compact at your end.
bernie probably has the best answer here (Copy whole worksheet) but your index error might be coming from:
par=[sheet.cell(row= col, column=1).value for col in range(1, 2450)]
being 1 cell shorter than:
for x in range(0,2450):
def excel_op():
filename='D://Python//excelread.xlsx'
sheet_name='Sheet1'
book = xlrd.open_workbook(str(filename))
sheet = book.sheet_by_name(sheet_name)
workbook = xlsxwriter.Workbook('excelwrite.xlsx')
worksheet = workbook.add_worksheet()
row_count = int(sheet.nrows)
col_count = int(sheet.ncols)
for row in range(0, int(row_count)):
for col in range(0, int(col_count)):
worksheet.write(row,col,str(sheet.cell(row, col).value))
workbook.close()
del book
shutil.copy("Source.xlsx", "target.xlsx")

Categories

Resources