My goal is to use write_array_formula and refer to a range of cells in another sheet. I'm trying this code:
workbook = xlsxwriter.Workbook('test.xlsx')
sheet1 = workbook.add_worksheet('Sheet1')
sheet2 = workbook.add_worksheet('Sheet2')
sheet1.write('A1', 'Foo')
sheet1.write('A2', 'Bar')
sheet1.write_array_formula('B1:B2', '{=Sheet1!$A$1:$A$2}')
sheet2.write_array_formula('B1:B2', '{=Sheet1!$A$1:$A$2}')
workbook.close()
With this code I was expecting for column B of Sheet1 and Sheet2 to be identical. But it appears that the formula is not being calculated in Sheet2.
Here's what column B looks like in Sheet 1:
And here's what column B looks like in Sheet 2:
It turns out that this was the result of a bug in XlsxWriter that went unnoticed for a long time.
It is fixed in XlsxWriter version 1.3.1 and later. Thanks.
Related
I will not put all my script, for the sake of clarity.
I created a workbook, where I stored data based on an csv files, then I created cells who contains sums of those data :
import openpyxl
wb = openpyxl.Workbook()
sheet = wb.active
sheet2=wb.create_sheet('somme')
sheet['C16'] = '= SUM(A100:A212)'
sheet['D16'] = '= SUM(B100:B212)'
sheet['E16'] = '= SUM(C100:C212)'
sheet['F16'] = '= SUM(D100:D212)'
But I want the sums to be in another sheet, but not the formula, just the value, because otherwise it will be 0 because in sheet2 there is no data to sum.
I tried this :
for row in sheet['A1':'Z100']:
for cell in row:
sheet2[cell.coordinate].value = cell.value
But it return formula, so I don't have the number, just 0.
Any ideas how to fix that ?
You could do this by having the cells in sheet2 reference the sum cells with a formula, like =Sheet1!C16.
If you already know the title of sheet, you can just use that directly. If not, it's probably a good idea to use openpyxl.utils.cell.quote_sheetname() to avoid potential issues with spaces:
sheet2[cell.coordinate].value = f"={quote_sheetname(sheet.title)}!{cell.coordinate}"
Another approach, if you don't want the sums in the main worksheet, would be to put the sum formulas directly in sheet2, and add the title of the first worksheet to the cell ranges.
I have two Sheets , Sheet1 and Sheet2. The column J in sheet1 contains, the Name of Project. I wanted the closing date of poject from sheet2. for this,
I am looking into sheet2 with Project Name of sheet1 and if they are same, then I copy the date to sheet1 in column w.
once, I have copied, then i compare the date in column u with the column w and say if it is ok or not ok.
I have formulated the above conditions in the form of formula.
But I wanted to have them in VBA. Could anyone suggest how i can Frame my formula in VBA.
Column W =IFERROR(VLOOKUP(J2;Sheet2!$A:$L;7;0);"")
Column X=IF($W2>$U2;0;1)
Column Y=IF($W2<=$U2;0;1)
I would not prefer to use recorded macros.
The easiest way is to record macro, when you activate and accept formula. The in VBA code I can find the right solutions.
For example:
IF($W2>$U2;0;1) for cell H3
Range("H3").Select
ActiveCell.FormulaR1C1 = "=IF(RC23>RC21,0,1)"
Range("H3").Formula = "=IF(RC23>RC21,0,1)"
I have column B with cost centre codes and column D with department. i need to do a vlookup to fill in the department name of the relevant cost centre code.
The current code is like this:
Dim MyStringVar1= Application.Vlookup(Range("B7"),_
Worksheets("VLOOKUP Table").Range("A2:B1000"),2,True)
However, i dont just want to do vlookup for D7 only but rather the entire column. My range is not fixed(there may be 100 or 200rows in Column B,depending on the number of projects.)
How do I apply the formula for the entire column? Instead of D7 only
let's say you want to add formula =VLOOKUP(B2,'VLOOKUP Table'!A$2:B$1000,2,TRUE)
to range D3:D10, where 'B2' will increment after every row, then the code would be :
Range("D3:D10").Formula= "=VLOOKUP(B2,'VLOOKUP Table'!A$2:B$1000,2,TRUE)"
Dim This As Worksheet
Set This = ThisWorkbook.Sheets(1)
This.Activate
This.Range("D7", Range("A2").End(xlDown).Offset(0, 3)).Formula = "=VLOOKUP(B2,[INSERT SHEET]!$A:$D,2,FALSE)"
If the data is in sheet2, you just insert sheet2 in the [INSERT SHEET]. It doesn't matter if the name is sheet2 or named something else, just call it sheet2
You could use relative references in an R1C1 formula, then just paste it to your destination range, you'd need to find the destination range first, perhaps using something like .end(xldown).row
See this for reference on the general idea:
http://macromatician.blogspot.co.uk/2013/02/how-to-add-formula-to-worksheet-range.html
Ok, the question sounds pretty vague, but i will try to explain.
I am trying to copy certain cell values from one sheet into another sheet. The place it should copy it to, is determined by another value in the same sheet. For example:
Sheet1
4040-5056 ----- 4040-5056v1.7
3409-5793 ----- 3409-5793v4.3
Sheet2
4040-5056
3409-5793
Based on the first values you see, the second column of values in sheet1 should be copied in the corresponding cells in sheet2.
I have no idea how to do this, any help would be appreciated!
Thanks in advance
EDIT:
Sheet1 contains all values that have to be copied to the corresponding nvalues in the other sheets.
The values it has to correspond with are spread over 30 sheets or so, but all in the same document. In every sheet the values the code has to look for are all in the same column, so in every sheet is should look whether the value is the same in column A. VLOOKUP works, but is still a slow option, knowing that is handles over 36.000 rows. What the code should do, is copy the value of column B to one of the other sheets, if the value of column A corresponds with the value of column A in the other sheet.
I hope everyone can understand this explanation.
You can use the VLOOKUP function. No need to use VBA for this.
Sheet 1 :
A B C
1 4040-5056 4040-5056v1.7
2 3409-5793 3409-5793V4.3
3
Sheet 2:
A B C
1 4040-5056 =VLOOKUP(A1;Sheet1!$A$1:$B$2;2;FALSE)
2 3409-5793 =VLOOKUP(A2;Sheet1!$A$1:$B$2;2;FALSE)
3
Cell B1 will display "4040-5056v1.7", cell B2 "3409-5793V4.3"
Note that the last argument to VLOOKUP (here FALSE) is important in your case since the data is unsorted.
Another solution, using pure VBA:
Since there is a strong need for performance, I suggest using a dict object, as hinted in this SO question. The advantage of using a dictionary is that it is very fast to lookup, once it is built. So I expect my code to be very quick in the lookup. On the other hand, it will be slower in accessing the individual cells (through loops) than the builtin VLOOKUP.
Comparative performance, using a reference sheet fof 30'000 entries, and 3 lookup sheets with 30'000 lines each:
VLOOKUP : 600 seconds
VBA / dictionary : 3 seconds
so the performance is 200x better with VBA dictionary in this context.
Note : you have to add a reference to "Microsoft Scripting Runtime" (from the tools->Reference menu of the VBA window)
Note : this solution will not work if the data in the reference sheet is not contiguous, or if there are duplicates.
Sub FillReferences()
Dim dict As New Scripting.Dictionary
Dim myRow As Range
Dim mySheet As Worksheet
Const RefSheetName As String = "sheet1"
' 1. Build a dictionnary
Set mySheet = Worksheets(RefSheetName)
For Each myRow In mySheet.Range(mySheet.Range("A1").End(xlDown), mySheet.Range("A" & mySheet.Rows.Count).End(xlUp))
' Append A : B to dictionnary
dict.Add myRow.Value, myRow.Offset(0, 1).Value
Next myRow
' 2. Use it over all sheets
For Each mySheet In Worksheets
If mySheet.Name <> RefSheetName Then
' Check all cells in col A
For Each myRow In mySheet.Range(mySheet.Range("A1").End(xlDown), mySheet.Range("A" & mySheet.Rows.Count).End(xlUp))
' Value exists in ref sheet ?
If dict.exists(myRow.Value) Then
' Put value in col B
myRow.Offset(0, 1).Value = dict(myRow.Value)
End If
Next myRow
End If
Next mySheet
End Sub
In both worksheets I have a key in column A. Not all of the key values are in both worksheets.
For each key value in column A of Worksheet 1, I want to find the corresponding key in worksheet 2 and move the data in column B of worksheet 2 into column B of worksheet 1.
I have never programmed a macro so I am completely lost for writing this code.
There is no need for VBA here, Philip.
Try this formula in cell B1 of Sheet1:
=IFERROR(vlookup(A1,Sheet2!A:B,2,false),"")
If you are on XL 2003, then do this:
=IF(ISERROR(vlookup(A1,Sheet2!A:B,2,false)),"",vlookup(A1,Sheet2!A:B,2,false))
Then drag this formula down for the rest of your data in Column A of Sheet1.
NB - Sheet2 is the assumed name of your Worksheet2, you may need to change to fit your needs.
NB2 - you can lookup vlookup in Excel Help (or online) to better understand what it does
Are you sure you need to use a macro for this? It sounds to me like you are using Excel and a simple VLOOKUP formula would do what you need.
A VLOOKUP looks like this: =VLOOKUP(A1,Sheet2!$A:$B,2,FALSE)
Where A1 is your reference cell (in this case you "key" in column A).
Sheet2!$A:$B is the lookup table (in this case columns A and B from the second sheet).
2 is the column number that you want data from, counting from the left (in this case the second column, column B)
FALSE tells the formula to only return values for exact matches. TRUE returns the closest match in the lookup table.