xlsxwriter click on cells or apply function - python

I have a python script that creates an Excel file.
Definition: Osisoft-function is a function inputted into an Excel cell to get data from an Osisoft server (there is installed a PI DataLink addon into Excel).
Definition 2: To apply an Osisoft-function means to click the cell that contains this function and in the showing menu (to the right) click "apply". Having applied this function, the list of time-value measurements fill the rows under this cell.
In this Excel file, there is written a lot of Osisoft-functions. But all of them need to be applied to actually get the data. It is possible to do it manually, but it becomes tedious when there are 100+ such functions.
The function is parsed into cell using command:
worksheet.write_array_formula(first_row, first_col, last_row, last_col, formula[,
cell_format[, value]])
My question: is it possible to write some kind of macro to click on all these cells and click the apply-buttons in the showing menus? Some kind of selenium-script, but for Excel.

You could write a vba macro like.
Dim Pl As Variant
Dim addIn As COMAddIn
Dim automationObject As Object
Set addIn = Application.COMAddIns("PI DataLink")
Set automationObject = addIn.Object
Worksheets("Sheet with Data").Activate
Worksheets("Sheet with Data").Range("Range ").Select
automationObject.SelectRange
automationObject.ResizeRange

Related

Opening an Excel File in Python Disables Dynamic Arrays

I have an excel workbook that uses functions like OFFSET, UNIQUE, and FILTER which spill into other cells. I'm using python to analyze and write some data to the workbook, but after doing so these formulas revert into normal arrays. This means they now take up a fixed number of cells (however many they took up before opening the file in python) instead of adjusting to fit all of the data. I can revert the change by selecting the formula and hitting enter, but there are many of these formulas it's more work to fix them than to just print the data to a text file and paste it into excel manually. Is there any way to prevent this behavior?
I've been using openpyxl to open and save the workbook, but after encountering this issue also tried xlsxwriter and the dataframe to excel function from pandas. Both of them had the same issue as openpyxl. For context I am on python 3.11 and using the most recent version of these modules. I believe this issue is on the Python side and not the Excel side, so I don't think changing Excel settings will help, but maybe there is something there I missed.
Example:
I've created an empty workbook with two sheets, one called 'main' and one called 'input'. The 'main' sheet will analyze data from the 'input' sheet which will be entered with openpyxl. The data will just be values in the first column.
In cell A1 of the 'main' sheet, enter =OFFSET(input!A1,0,0,COUNTA(input!A:A),1).
This formula will just show a copy of the data. Since there currently isn't any data it gives a #REF! error, so it only takes up one cell.
Now I'll run the following python code to add the numbers 0-9 into the first column of the input sheet:
from openpyxl import load_workbook
wb = load_workbook('workbook.xlsx')
ws = wb['input']
for i in range(10):
ws.append([i])
wb.save('workbook_2.xlsx')
When opening the new file, cell A1 on the 'main' sheet only has the first value, 0, instead of the range 0--9. When selecting the cell, you can see the formula is now {=OFFSET(input!A1,0,0,COUNTA(input!A:A),1)}. The curly brackets make it an array, so it wont spill. By hitting enter in the formula the array is removed and the sheet properly becomes the full range.
If I can get this simple example to work, then expanding it to the data I'm using shouldn't be a problem.

Excel removes a formula set by Pandas, but setting the formula manually makes the formula work

After check this post and see that there is no response I have opened this one.
I am trying to set a formula in an Excel cell through Pandas in Python. So far it worked by specifying the formula as text but with a new formula I am having problems:
=FILTER(SHEET1!A2:I456,(IF(SHEET2!D9=0,SHEET1!D2:D456>SHEET2!D9,SHEET1!D2:D456>=SHEET2!D9)),"No data")
(In the python code, the " are specified as \" for the empty branch)
If I open the Excel file after the code execution, Excel complains that there is a problem and I have to do accept a "recover", showing that the formula has been removed and the cell displays a 0.
After that, If I put the same formula (with " instead of \") manually in the same cell it works and the information is displayed.
I have tried to specify the cells with $ ($A$2) without success... I also have checked in the Excel options and the formulas are set to evaluate in "Automatic".
What is the problem?
Regards.
After some more research I have found the problem. I'm using OFFICE 365, in case it might affect this answer.
What was driving me crazy was that the handwritten formula in Excel was working. I had a workaround that consisted of putting the contents of the formula as text without the = sign so that Excel would not interpret it as a formula. Open Excel, go to that cell, enter the = by hand and when I pressed enter, the data was displayed.
As I use EXCEL in Spanish, but with Pandas you have to write everything in English notation, I thought I would see what Excel did internally when I put the = by hand and the formula worked. What I did was:
Change the file extension from .xlsx to .zip.
Open the zip and go to the path: xl/worksheets/sheet[number].xml.
Find the formula field, looking for <f> or </f>.
At that point I noticed that the content, instead of starting with:
FILTER(....)
I found:
_xlfn._xlws.FILTER(....)
So in the PANDAS code I changed:
cell_formula = f"=FILTER(...)"
by:
cell_formula = f"=_xlfn._xlws.FILTER(...)"
And then:
workbook = pandas_writer.book
worksheet = workbook.sheetnames[sheet_name]
worksheet.write_array_formula("A2:Y109", "{" + cell_formula + "}")
workbook.close()
And now when I open Excel I don't get the error and the formula shows the result. Then, looking in this section of the XlsxWriter documentation and in the Microsoft documentation this function does not appear.
So if this happens to you, fix the function by hand, save the changes and inspect the internal XML that is generated by EXCEL.

Python xlwings: Insert and calculate a non-english Excel-formula into xlsm

I want to set an excel formula with the python module xlwings in a xlsm file.
When I set it with the .value function of xlwings the formula gets entered into the file correctly, but on opening the file the formula is not calculated. Instead the cell is displayed as the following Error:
"#NAME?"
Upon clicking into the cell and pressing the "ENTER"-key it gets calculated correctly. However I obviously do not want to do this for millions of rows / cells in which I entered a formula with Python.
Here is the code I used to insert a value and a formula:
import xlwings as xw
workbook = xw.Book('filename.xlsm')
import_sheet = workbook.sheets['my_sheet']
# setting a value
import_sheet['A1'].value = 401 # works as expected.
# setting a function
import_sheet['B1'].value = '=ZEILE()' # is not displayed correctly
The solution is quite simple but not obvious:
Changing the formula to its english counterpart calculates and displays the formula correctly (and even translates it into the language of my excel when I open the file):
import_sheet['B1'].value = '=ROW()'
My assumption is that it is connected to xlwings language / function processing functionalities? Just a hunch though.

How to apply conditional formatting in openpyxl?

I am using openpyxl to manipulate a Microsoft Excel Worksheet.
What I want to do is to add a Conditional Formatting Rule that fills the rows with a given colour if the row number is even, leaves the row blank if not.
In Excel this can be done by selecting all the worksheet, creating a new formatting rule with the text =MOD(ROW();2)=0 or =EVEN(ROW()) = ROW().
I tried to implement this behaviour with the following lines of code (considering for example the first 10 rows):
redFill = PatternFill(start_color='EE1111', end_color='EE1111', fill_type='solid')
ws2.conditional_formatting.add('A1:A10', FormulaRule(formula=['MOD(ROW();2) = 0'], stopIfTrue=False, fill=redFill))
My program runs correctly but when I try to open the output Excel file, it tells me that the file contains unreadable content and it asks me if I want to recover the worksheet content. By clicking yes, the worksheet is what I expect but there is no formatting.
What is the correct way to apply such a formatting in openpyxl (possibly to the entire worksheet)?
Unfortunately, the way formulae are handled in conditional formatting is particularly opaque. The best thing to do is to create a file with the relevant conditional format and inspect the relevant file by unzipping it. The rules are stored in the relevant worksheet files and the formats in the styles file.
However, I suspect that the problem may simply because you are using ";" to separate parameters in the function: you must always use commas for this.
A sample formula from one of my projects:
green_text = Font(color="006100")
green_fill = PatternFill(bgColor="C6EFCE")
dxf2 = DifferentialStyle(font=green_text, fill=green_fill)
r3 = Rule(type="expression", dxf=dxf2)
r3.formula = ["AND(ISNUMBER(C2), C2>=400)"]

Use excel workbook like a function

I found this on a related subject - Excel function to make SQL-like queries on worksheet data?
But I was wondering if there is any way to use an excel workbook/file like a function in a separate workbook/file? So I have an excel workbook that has a control page - where I can input parameters 1,2,3. And based on those parameter, the outpage page will display the correlating data. I know I can duplictae the output page to show the outputs for all three parameters and link these to my other workbook.
However, is there any way to (in the other excel file) do something like FILENAME_otherfile.function(1).range(A1) or something? to extract the cell A1 with parameter 1 as an input? And in the same file also call FILENAME_otherfile.function(2).range(A1)?
There is a very inelegant way of doing it, but we can keep the interface as pretty as possible.
Open the workbook with a Application.Workbooks.Open()
Set its attribute to Hidden for aesthetic reasons.
Say you want to manipulate cells on "Sheet1" then Set InputRange and OutputRange (cells where you'll see the outputs) to the appropriate ranges in the opened workbook.
Change InputRange.Cells(m,n).Value
Get into some variable what happens, for e.g.
Dim MyAnswer as Double
MyAnswer = OutputRange.Cells(x,y)
Close the workbook, preferably not saving it (as your programming logic requires) and use the MyAnswer value as your 'function' output.

Categories