Hi I have a pretty complex spreadsheet and I need to update "ONLY" certain part of its contents.
I tried openpyxl, which works ok except all the pivot tables, styles and formulas are lost, after save the workbook. Is there a way to get around that?
Check which version of openpyxl you have installed. Support for Pivot Tables was only added in version 2.5.0-a1 (2017-05-30), and that only supported one Pivot Table until version 2.5.0-b2 (2018-01-19). See changelog.
Alternatives: Simplify, xlwings, content protection, and win32com (most likely).
If you are using 2.5 and it doesn't work, you'll probably have to simplify your spreadsheet if you want to continue to use openpyxl. E.g. split it into a source and output file, and use python to update the source file.
You could try running xlwings to host the Python code inside of the spreadsheet itself.
Another possible solution would be to lock the contents - turn on protection - for all except the sections you plan to update. This is unlikely to work as python is changing the contents directly, but it may respect the lock.
Finally, the result most likely to work. Drive the changes through the win32com module. I think this, unlike openpyxl, requires Excel to be installed as it is using Excel's functionality to make the changes. Examples of usage are here and here.
A brief example (taken from here):
import win32com.client as win32
excel = win32.gencache.EnsureDispatch('Excel.Application')
wb = excel.Workbooks.Add()
ws = wb.Worksheets("Sheet1")
ws.Cells(1,1).Value = "Cell A1"
ws.Cells(1,1).Offset(2,4).Value = "Cell D2"
ws.Range("A2").Value = "Cell A2"
ws.Range("A3:B4").Value = "A3:B4"
ws.Range("A6:B7,A9:B10").Value = "A6:B7,A9:B10"
wb.SaveAs('ranges_and_offsets.xlsx')
excel.Application.Quit()
Related
I've run into a problem while trying to automate SOLIDWORKS API VBA PackAndGo.
The order of action I take are:
Programmatically open an assembly
Programmatically modify this assembly and it's components while renaming the modified components
Programmatically engage pack and go
The unexpected problem is that the exported components have a correct / changed filename (as expected and as intended) but the actual models are the original none modified ones. This is something that I've only come across while trying to programmatically engage PackAndGo. When I do this routine manually from this modified assembly - the models that get renamed and exported are the actual new / modified ones.
My question is: "Why does this happen and how do I make it export teh models from active model?"
The code without the renaming routine etc. that I have written is:
Sub PackAndGo ()
'Set variables
Set swPackAndGo = swRootAssembly.Extension.GetPackAndGo
'Pack And Go
With swPackAndGo
.IncludeDrawings = True
.SetSaveToName True, OutputDirectory
.GetDocumentNames DocumentNamesArray
.GetDocumentSaveToNames DocumentSaveToNamesArray, 0
'Here I do the renaming of components in DocumentSaveToNamesArray
.SetDocumentSaveToNames DocumentSaveToNamesArray
.FlattenToSingleFolder = True
End With
'Pack and go
swRootAssembly.Extension.SavePackAndGo swPackAndGo
End Sub
Maybe I'm missing some additional method or function to make it copy the opened / active assembly components, rather than ones from the hard drive which are in fact the same models, but are not modified or altered in any way.
A simple example would be that I programmatically open a brick that's 20mm long and then programmatically change it's length to 50mm. Now I expect packandgo to save / export this 50mm long one but what it in fact does when run programmatically is export the same 20mm long brick, but with a different filename (again, different filename is what is expected)
Please can someone give me an example, how to copy
a whole worksheet with styles (from rows and columns)
to a second worksheet in the same workbook ?
(in a new workbook would also be possible)
Thank you.
P.S.: I tried to do a deepcopy, but that failed on saving changed data cells.
Purpose is: I try to fill some worksheets with my data and the first worksheet is my template.
I was successful in copying the values but only some styles.
I am using the latest version of openpyxl, so please no 1.x methods.
Version 2.4 will allow you to do this: copy_worksheet
>>> source = wb.active
>>> target = wb.copy_worksheet(source)
For older ones you can probably copy the source code from here
UPDATE: You can't simply graft this code into older versions of the library
You can't do this easily. The best approach is probably the one described in bug 171
I had the same problem. I solved using copy instead deepcopy. I found the solution on this site
I hope this works for you!
Regarding the links for the Openpyxl repository on #charlie-clark and #sam answers, these are not working anymore since the repo was moved from Bitbucket to Gitlab.
The updated link for issue 171 is https://foss.heptapod.net/openpyxl/openpyxl/-/issues/171
Notice that the copy_worksheet method does not copy data validations. You can do this manually using openpyxl's add_data_validation. A full working example:
# Copy worksheet
workbook = openpyxl.load_workbook(source_excel)
sheet_to_copy = workbook[sheet_name]
new_sheet = workbook.copy_worksheet(sheet_to_copy)
new_sheet.title = new_sheet_name
# Copy data validations
for data_validation in sheet_to_copy.data_validations.dataValidation:
new_sheet.add_data_validation(data_validation)
# Save result
workbook.save(source_excel)
I'm fairly new to this stuff, so hopefully someone our there can help me out.
The setup: I've got an Access 2007 database that imports data, then performs a set of queries and exports the results on a monthly basis.
The monthly data is saved as either Excel spreadsheets or in text files in a "Current" folder. I saved the rather tedious import steps for each file to facilitate the process of adding them as tables in Access.
There are a lot of files to import, so I wrote a simple VBA code to run all of the saved imports at once.
Public Sub DatabaseImp()
DoCmd.RunSavedImportExport "Import-Excel1"
DoCmd.RunSavedImportExport "Import-Excel2"
DoCmd.RunSavedImportExport "Import-Txt1"
DoCmd.RunSavedImportExport "Import-Txt2"
DoCmd.RunSavedImportExport "Etc....."
End Sub
Also, I created a macro to run this code and everything works fine.
BUT,
The Problem: Depending on the month, certain files will be included in the 'Current' folder and others won't be.
For example, suppose that this month there is no 'Excel2' file to import into the database.
Is there anyway to modify the code above so that it only tries to perform the import IF there is something there for it to import?
I understand that I could simply do it manually, ignoring the 'Excel2' import. However I would like to keep the process automated.
I'm looking for some kind of conditional IF statement that I could add on to the end of each line, e.g.:
DoCmd.RunSavedImportExport "Import -Excel1"
(ONLY IF there is an excel1 file in the 'current' folder to import)
Ideas, anyone?
Thanks,
You can use the Dir command. If the result is is an empty string, then it doesn't exist.
So, on a Windows machine, Dir("C:\Windows\explorer.exe") will return explorer.exe, but Dir("C:\Windows\bumblebee.exe") will return "".
So set up an If statement.
If Len(Dir(YourFile)) > 0 then
DoCmd.RunSavedImportExport "Import -Excel1"
End if
I'd like to be able to ready an excel file by column index, row by row, in VB .NET.
I can do it extremely easily with python XLRD, and with vb6 via "ADOX.Catalog"
Basically, this should be enough for my needs:
wb = open(excelfile)
ws = wb.worksheet(0)
cell = ws.get_cell(col, row)
How can I do that?
Is there a way to get the columns of a worksheet?
I haven't found any documentation of NPOI
I haven't found any *.vb file samples in the NPOI downloads (alpha, beta and stable versions)
is there a unified excel file opener that will detect the file version and pick up the correct opener class, or do i have to do it by file extension?
subjective question: am I the only one who think this API is overly complex?
IMPORTANT EDIT: I CAN'T INSTALL EXCEL ON THE MACHINE, so i'm looking for non-excel solutions
ps. i'm new to .net
Not sure what npoi is, but this may help, assuming you have declared them:
xlObject = new excel.application()
xlWB = xlObject.workbooks(0) // I think it also takes string (name of wb)
sheet = xlWB.worksheet(0)
sheet.Range("B2") //specific cell
Are you talking about xls vs xlsx? It should handle both fine...
And NO! It's not nearly as intuitive or simple as it should be!
I have a folder with several excel files that have a date field, i.e. 08-24-2010-123320564.xls. I want to be able to have some VB scripting that will simply take the files that start with todays date and merge them into one file.
08-24-2010-123320564.xls
08-24-2010-123440735.xls
08-24-2010-131450342.xls
into
08-24-2010.xls
Can someone please help?
Thanks
GabrielVA
assuming you just want to append rows in simple spreadsheets, follow this logic:
Psuedocode
use an excel macro
(you could just as well automate excel from vb but why vbscript alone since you need excel anyway?)
have it to a dir listing (dir function)
dim a date_start variable init to "new"
dim a merged_spreadsheet as new doc default to nothing
loop thru result of dir
if date_start <> start of filename
if merged_spreadsheet is not nothing
save it
set it to nothing
store start of date (left mid function) in date_start
if merged_spreadsheet is nothing
make a new one
open the file from the dir command's loop
select all the data
copy it
go to first empty row in merged_spreadsheet
paste it
loop files
if merged_spreadsheet is not nothing
save it
If you're not happy with all those 'nothings', you can set a separate flag to keep track of whether you have a merged_spreadsheet or not. Think about what happens for just one file in a date, no files at all, etc.
Of course you will tear out your hair finding out how to automate those excel functions. The secret to turning 'hard' into 'pretty darn easy' is this:
macro recorder will reveal the automation commands
They are not intuitive. So record a macro. Then do things that you'll need to do in your code. Stop recording and look at the result.
For example:
* load/save files
* select only entered fields
* Select all
* copy / switch files / paste
* create new sheet
* click in various single cells and type (how to examine/set a cell's contents)
In summary-
(1) Know exactly the steps to what you're doing
(2) Use macro recorder to give away the secrets of the excel object model. Steal its secrets.
Really this won't be all that hard if you marry these two concepts cleverly. Since the macro will be vbscript (at least if you use office 97 ;-) you can probably run it from vbs or vb6 if you want. A hop to vb.net shouldn't be that hard either.
Aspose makes it pretty easy to work with excel-files in .NET http://www.aspose.com