I'm trying to save dataframes into tabs/sheets in an existing xlsm file. I was able to save multiple sheets into an xlsx file with engine=xlsxwriter but couldn't find a way to modify it to write to a xlsm file. I found numerous examples using openpyxl as an engine but haven't found a way to predefine the cell formats. Here's the xlswriter code:
with pd.ExcelWriter(filename + '.xlsx', engine='xlsxwriter') as writer:
df.to_excel(writer, sheet_name=tabname)
workbook = writer.book
worksheet = writer.sheets[tabname]
fmt0 = workbook.add_format({'num_format': '0'})
fmt1 = workbook.add_format({'num_format': '0.0'})
fmt2 = workbook.add_format({'num_format': '0.00'})
for r in range(len(df.index)):
s = r + 1
cols = {3: 'min', 4: 'max'}
for c in cols:
v = df.at[df.index[r], cols[c]]
if is_number(v):
if '.' not in v:
worksheet.write_number(s, c, float(v), fmt0)
else:
pl = len(v) - v.index('.') - 1 # number of digits after '.'
if pl == 1:
worksheet.write_number(s, c, float(v), fmt1)
elif pl == 2:
worksheet.write_number(s, c, float(v), fmt2)
Does openpyxl have a way to do the same thing?
I think I can define a function that will do this but if there's a way to modify the existing code, I'd rather do that.
I'm updating a VBA script and trying to match a 4-digit code with a table and printing the two corresponding columns into my original sheet, plus handling codes missing from the reference table.
jobcodes = sample codes to match.
codematch = reference table, 1st column is reference codes, I want the corresponding values in columns 2 and 3 in K and L of "jobcodes".
At the minute I'm getting blank values in the first two rows, then #N/A errors in the rest of the sample table.
finrow3 = jobs.Cells(Rows.Count, 1).End(xlUp).Row
jobcodes = jobs.Range(("J2"), ("L" & finrow3)).Value
codematch = stat.Range("I2:K143").Value
For i = 1 To finrow3 - 1
For j = 1 To UBound(codematch, 1)
If StrComp(jobcodes(i, 1), codematch(j, 1)) = 0 Then
resulta(z, 1) = codematch(j, 2)
resulta(z, 2) = codematch(j, 3)
Else
resulta(z, 1) = ""
resulta(z, 2) = ""
End If
Next j
Next i
jobs.Range(("K2"), ("L" & finrow3)).Value = Application.Transpose(resulta)
With the below code I am trying to format cells when certain names appear in a drop down list(cell C4) and format these specific cells in Range G9:N9. But when I run the code it converts all numbers into percents appose to differentiating between the two formatting styles (Percent and General). Can anyone help?
Sub LetsMakeThisWork()
With Worksheets("Geo")
If C4 = V2 Or C4 = x2 Or C4 = AB2 Or C4 = AD2 Or C4 = AG2 Or C4 = AM2 Or C4 = AO2 Or C4 = AQ2 Or C4 = AU2 Or C4 = AW2 Then
ActiveCell.Range("G9:N9").NumberFormat = "0.0%"
Else
ActiveCell.Range("G9:N9").NumberFormat = "General"
End If
End With
End Sub
In context, you intend C4, V2 etc. to be a cell references but VBA is interpreting them as variables. The fact that your code runs at all in that case implies that you are not using Option Explicit, which you really should use in VBA. What seems to be happening is that you are implicitly creating empty variables in the process of testing them for equality. Any two empty variables are equal, hence the first clause of the If statement is always run. Corrected, but not tested, your code should (I think) look like this:
Option Explicit
Sub LetsMakeThisWork()
Dim C4 As Range
With Worksheets("Geo")
Set C4 = .Range("C4")
If C4.Value = .Range("RV2").Value Or C4.Value = .Range("X2").Value Or _
C4.Value = .Range("AB2").Value Or C4.Value = .Range("AD2").Value Or _
C4.Value = .Range("AG2").Value Or C4.Value = .Range("AM2").Value Or _
C4.Value = .Range("AO2").Value Or C4.Value = .Range("AQ2").Value Or _
C4.Value = .Range("AU2").Value Or C4.Value = .Range("AW2").Value Then
.Range("G9:N9").NumberFormat = "0.0%"
Else
.Range("G9:N9").NumberFormat = "General"
End If
End With
End Sub
Need help with writing this Excel function into a Macro, please help
A1=7 B1=1 C1=4
A2=8 B2=2 C2=5
A3=9 B3=3 C3=6
if A1 = A1(7), answers will equal to B1 * C1 = 1*4 = 4
if A1 = A2(8), answers will equal to B2 * C2 = 2*5 = 10
the function works perfectly in the excel cell,
SUMPRODUCT((A1:A3=A1)+0,B1:B3,C1:C3)
however, the vba doesn't not work.
With Worksheets("Sumproduct")
.Range("D1").Value = Application.WorksheetFunction.SumProduct((.Range("A1:A3" = A1)+ 0 , .Range("B1:B3"), .Range("C1:C3"))`
This is my first foray into user defined functions since Excel 7.0. So I'm pretty sure I'm making a newbie error.
I'm getting a #VALUE error in the cell where I've entered the formula. When I use Error Checking to Show Calculation Steps, it evaluates the functions arguments as the cell references rather than values.
The formula in the cell:
=PavementNPV(P2, U2, T2, R2, Y2, Z2, AA2, I2, J2, K2, B2, W2, V2, X2)
Error checking window says the formula exactly with all cell references underline and X2 italicized. At the bottom is the message that the next evaluation will cause an error. The error is #VALUE.
The values in the cells:
P2 = 10
U2 = 63.17986
T2 = 10
R2 = 3
Y2 = $0.28
Z2 = $1.32
AA2 = $2.58
I2 = 14000
J2 = 45
K2 = 60
B2 = 292
W2 = 73.17986
V2 = 8
X2 = 0.05
The code:
Function PavementNPV(AssumedLife, PvmtCondition, AgeByCondition, Curve, CarVOC As Currency, BusVOC As Currency, TruckVOC As Currency, AvgDailyTraffic, TruckCount, BusCount, SegLength, RestPCTGain, RestAgeByCondition, Rate) As Currency
'Calculate Yr1 restored PCI(PvmtCondition - Pavement Condition Index) value
' =PvmtCondition + Assumed Life
Dim Yr1RestPCI
Yr1RestPCI = PvmtCondition + AssumedLife
'For each year of Assumed life, calculate doNothingTotalAnnualVOCIncreaseRange and restoredTotalAnnualVOCIncreaseRange:
' =365*(CarVOCIncrease% as (Application.WorksheetFunction.VLOOKUP((PCIofYr as (If Yr1 then PvmtCondition, else 100*(1/(1+EXP((AgeByCondition+year(e.g. 2)-1)/Application.WorksheetFunction.VLOOKUP(Curve,Table4[#All],2,FALSE)-Application.WorksheetFunction.VLOOKUP(Curve,Table4[#All],3,FALSE))))*Application.WorksheetFunction.VLOOKUP(Curve,Table4[#All],4,FALSE)))),'User Cost'!$BC$5:$BF$151,2))*CarVOC*AvgDailyTraffic+BusVOCIncrease%*BusVOC+TruckVOCIncrease%*TruckVOC)*SegLength/5280)
Dim arydoNothingPCI()
ReDim arydoNothingPCI(1 To AssumedLife)
Dim aryRestoredPCI()
ReDim aryRestoredPCI(1 To AssumedLife)
Dim arydoNothingVOCIncrease() As Currency
ReDim arydoNothingVOCIncrease(1 To AssumedLife)
Dim aryRestoredVOCIncrease() As Currency
ReDim aryRestoredVOCIncrease(1 To AssumedLife)
Dim i
arydoNothingPCI(1) = PvmtCondition
aryRestoredPCI(1) = Yr1RestPCI
For i = 2 To AssumedLife
arydoNothingPCI(i) = 100 * (1 / (1 + Application.WorksheetFunction.Exp((AgeByCondition + i) - 1) / Application.WorksheetFunction.VLookup(Curve, "Table4[#All]", 2, False) - Application.WorksheetFunction.VLookup(Curve, "Table4[#All]", 3, False))) * Application.WorksheetFunction.VLookup(Curve, "Table4[#All]", 4, False)
aryRestoredPCI(i) = 100 * (1 / (1 + Application.WorksheetFunction.Exp((RestAgeByCondition + i) - 1) / Application.WorksheetFunction.VLookup(Curve, "Table4[#All]", 2, False) - Application.WorksheetFunction.VLookup(Curve, "Table4[#All]", 3, False))) * Application.WorksheetFunction.VLookup(Curve, "Table4[#All]", 4, False)
Next
'Testing function so far by asking it to return something simple
PavementNPV = CarVOC
'Calculate Total PV Benefits by calculating NPV of doNothing minus NPV or restored
' =Application.WorksheetFunction.NPV(rate,doNothingTotalAnnualVOCIncreaseRange)- Application.WorksheetFunction.NPV(rate,restoredTotalAnnualVOCIncreaseRange)
' or for each NPV =(Yr1VOCIncrease/(1+rate)^1)+(Yr2VOCIncrease/(1+rate)^2)+(Yr3VOCIncrease/(1+rate)^3) etc for all years
End Function
I originally had all of the data types defined, but removed those as my first troubleshooting step. I also originally had the formula entered using Table references (e.g. [#columnname]). I would love to be able to return to that for readability.
Please let me know if you need any additional information to help. Thank you in advance.
Your parameters Arg2 of WorksheetFunction.VLookup are not correct. They can't be strings.
Use
Application.WorksheetFunction.VLookup(Curve, Application.Range("Table4[#All]"), 2, False)
for example.
Another error could be that the WorksheetFunction.VLookup returns the #N/A error because the lookup value could not be found within the table array. In this case the function breaks at this point and returns #Value also. This you could avoid using On Error Resume Next before the calls of WorksheetFunction.VLookup and On Error GoTo 0 after them.
Hint to debug: Have the VBA Editor open. Set a breakpoint somewhere in the function's body. Call the function by input it as formula in a cell. The code stops at the breakpoint. Change to the VBA Editor window and step through the code.