Conditionally format unique rows in a pivot table, and transfer this formatting to other cells without the rules or values - excel

I have a pivot table which summarizes three key figures for each individual item in our inventory over a six week time frame.
I want to conditionally format with a color scale the six cells in the "Supplier Inventory DOH" rows for each individual item.
Once those six cells are formatted, I want to copy those colors to the coordinating six cells below in "Total Inventory" without the rules or values which come with the formatting typically.
The purpose of this is to show the Days on Hand risk by color scale, in coordination with the current inventory - think of it as layering formatting on top of the inventory values.
For the formatting process alone I found a similar related discussion referencing this article: Excel conditional colour scale for multiple rows, and I tried using the code it included in the comments. I changed the code and its references to match what I would need- knowing full well that this code is meant just for a blanket drag and drop over all of the data-not for the unique rows themselves. If this code worked I hoped it would be a start at least- however after running it through it didn't do anything. I am wondering if some of this code is incorrect, what kind of code I would add in to only format the rows with the Supplier Inventory DOH description, or if there was a better way to do this?
For the copying formatting piece, I found a related article discussion: How to copy the conditional formatting without copying the rules from a Conditional Formatted cell?, however copy and pasting just the color themselves did not work on my Windows 10 excel version. Is there a way to do this process as well?
Original version of code:
Option Explicit
Sub ApplyConditionalFormatting()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet1") ' change to your sheet here
Dim rw As Long
Dim rng As Range
For rw = 3 To 8 ' change to your respective rows
With ws
Set rng = .Range(.Cells(rw, "E"), .Cells(rw, "K")) ' change to your respective columns
With rng
.FormatConditions.AddColorScale ColorScaleType:=3
.FormatConditions(.FormatConditions.Count).SetFirstPriority ' now its index is 1, in case there already was cond formatting applied
End With
With rng.FormatConditions(1)
With .ColorScaleCriteria(1)
.Type = xlConditionValueNumber
.Value = 0
.FormatColor.Color = 7039480
End With
With .ColorScaleCriteria(2)
.Type = xlConditionValueFormula
.Value = "='" & ws.Name & "'!$D$" & rw & "*3" ' References column D, change as needed
.FormatColor.Color = 8711167
End With
With .ColorScaleCriteria(3)
.Type = xlConditionValueFormula
.Value = "='" & ws.Name & "'!$D$" & rw & "*5" ' References column D, change as needed
.FormatColor.Color = 8109667
End With
End With
End With
Next rw
End Sub
My version of the code:
Sub CF()
'
' CF Macro
'
' Keyboard Shortcut: Ctrl+f
'
End Sub
Public Sub Formatting()
Option Explicit
Sub ApplyConditionalFormatting()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet2")
Dim rw As Long
Dim rng As Range
For rw = 6 To 1764
With ws
Set rng = .Range(.Cells(rw, "B"), .Cells(rw, "G"))
With rng
.FormatConditions.AddColorScale ColorScaleType:=3
.FormatConditions(.FormatConditions.Count).SetFirstPriority
End With
With rng.FormatConditions(1)
With .ColorScaleCriteria(1)
.Type = xlConditionValueNumber
.Value = 40
.FormatColor.Color = 7039480
End With
With .ColorScaleCriteria(2)
.Type = xlConditionValueFormula
.Value = 70
.FormatColor.Color = 8711167
End With
With .ColorScaleCriteria(3)
.Type = xlConditionValueFormula
.Value = 80
.FormatColor.Color = 8109667
End With
End With
End With
Next rw
End Sub
End Sub
I expect the rows for each individual items DOH to be conditionally formatted based on the rule I need in an automated process that doesn't include going row by row with format painter. Then, to be able to copy those colors to the Total Inventory cells below (without the rules or values) to be able to show the correlation between Days on Hand and what is left in the inventory.
Pivot Table with Rule:
Pivot table with desired formatting:

You can get all relevant cells by PivotSelect,
then add your desired conditional formatting to them,
and use the resulting DisplayFormat.Interior.Color as Interior.Color for your "Total Inventory" cells.
Private Sub ConditionalFormattingforSNCPlanning()
Dim ws As Excel.Worksheet
Dim pt As Excel.PivotTable
Dim fc As Excel.FormatCondition
Dim cs As Excel.ColorScale
Dim strDOH As String, strTotal As String
Dim rngSource As Range, rngDest As Range, rngCell As Range, strDest() As String
Set ws = ActiveWorkbook.Sheets("Sheet2")
Set pt = ws.PivotTables(1)
strDOH = "'SNC PLANNING' 'Supplier Network DOH'"
strTotal = "'SNC PLANNING' 'Total Inventory'"
' Delete all conditional colors and normal interior colors first
With pt.TableRange2
.FormatConditions.Delete
.Interior.ColorIndex = xlNone
.Interior.Pattern = xlNone
End With
' Show all pivottable rows, as otherwise PivotSelect may fail
Dim i As Long
For i = pt.RowFields.Count To 2 Step -1
pt.RowFields(i).ShowDetail = True
Next i
' select all desired rows for conditional formatting
pt.PivotSelect _
Name:=strDOH, _
Mode:=XlPTSelectionMode.xlDataOnly, _
Usestandardname:=True
' if you don't want to delete every conditional format
' by above pt.TableRange2.FormatConditions.Delete
' then use following line here instead
' Selection.FormatConditions.Delete
' Add a new conditional formatting (3-Color Scale)
Set cs = Selection.FormatConditions.AddColorScale(ColorScaleType:=3)
With cs.ColorScaleCriteria(1)
.Type = xlConditionValueNumber
.Value = 40
.FormatColor.Color = RGB(248, 105, 107) ' 7039480
.FormatColor.TintAndShade = 0
End With
With cs.ColorScaleCriteria(2)
.Type = xlConditionValueNumber
.Value = 70
.FormatColor.Color = RGB(255, 235, 132) ' 8711167
.FormatColor.TintAndShade = 0
End With
With cs.ColorScaleCriteria(3)
.Type = xlConditionValueNumber
.Value = 80
.FormatColor.Color = RGB(99, 190, 123) ' 8109667
.FormatColor.TintAndShade = 0
End With
' Get both ranges for later color-copy-code
Set rngSource = Selection
pt.PivotSelect _
Name:=strTotal, _
Mode:=XlPTSelectionMode.xlDataOnly, _
Usestandardname:=True
Set rngDest = Selection
' Exit if both range's cell count not equal
If rngSource.Cells.Count <> rngDest.Cells.Count Then
MsgBox "Sorry, this works only, if cell count is identical"
Exit Sub
End If
' store all addresses of the destination range's cells
ReDim strDest(1 To rngDest.Cells.Count)
i = 1
For Each rngCell In rngDest.Cells
strDest(i) = rngCell.AddressLocal
i = i + 1
Next rngCell
' copy source's DisplayFormat.Interior.Color
' to destination's Interior.Color
' cell by cell
i = 1
For Each rngCell In rngSource.Cells
ws.Range(strDest(i)).Interior.Color = rngCell.DisplayFormat.Interior.Color
i = i + 1
Next rngCell
End Sub

This is a different approach with a loop over the PivotTable.RowRange. When the desired terms are found, the corresponding row of the PivotTable.DataBodyRange is coloured.
The "Source" (e. g. "Supplier Network DOH") is formatted via conditional formatting and the "Destination" (e. g. "Total Inventory") gets the displayed color of the previously conditional formatted row as interior color.
Private Sub ConditionalFormattingforSNCPlanningVersion2()
Dim ws As Excel.Worksheet
Dim pt As Excel.PivotTable
Dim fc As Excel.FormatCondition
Dim cs As Excel.ColorScale
Dim SourceString As String, DestString As String
Dim SourceIsFound As Boolean
Dim SourceRow As Long, DestRow As Long
Dim CellInColumn As Range, CellInRow As Range
Set ws = ActiveWorkbook.ActiveSheet
Set pt = ws.PivotTables(1)
SourceString = "Supplier Network DOH"
DestString = "Total Inventory"
' Delete all conditional colors and normal interior colors first
With pt.TableRange2
.FormatConditions.Delete
.Interior.ColorIndex = xlNone
.Interior.Pattern = xlNone
End With
' Show all pivottable rows
Dim i As Long
For i = pt.RowFields.Count To 2 Step -1
pt.RowFields(i).ShowDetail = True
Next i
' loop all cells in last column of rowrange
For Each CellInColumn In pt.RowRange.Columns(pt.RowRange.Columns.Count).Cells
' If row is source, then add conditional formatting
If CellInColumn.Value = SourceString Then
SourceIsFound = True
SourceRow = CellInColumn.Row
Set cs = Intersect(ws.Rows(SourceRow).EntireRow, pt.DataBodyRange).FormatConditions.AddColorScale(ColorScaleType:=3)
With cs.ColorScaleCriteria(1)
.Type = xlConditionValueNumber
.Value = 40
.FormatColor.Color = RGB(248, 105, 107) ' 7039480
.FormatColor.TintAndShade = 0
End With
With cs.ColorScaleCriteria(2)
.Type = xlConditionValueNumber
.Value = 70
.FormatColor.Color = RGB(255, 235, 132) ' 8711167
.FormatColor.TintAndShade = 0
End With
With cs.ColorScaleCriteria(3)
.Type = xlConditionValueNumber
.Value = 80
.FormatColor.Color = RGB(99, 190, 123) ' 8109667
.FormatColor.TintAndShade = 0
End With
End If
' If cell is destination, then copy color of previously found sourcerow
If CellInColumn.Value = DestString Then
If SourceIsFound Then
DestRow = CellInColumn.Row
For Each CellInRow In Intersect(ws.Rows(SourceRow).EntireRow, pt.DataBodyRange).Cells
ws.Cells(DestRow, CellInRow.Column).Interior.Color = CellInRow.DisplayFormat.Interior.Color
Next CellInRow
SourceIsFound = False
End If
End If
Next CellInColumn
End Sub

Related

columns values from two different sheet copy pasted in to another sheet and then comparing side by side cell and coloring them with green if matching

sub copycolmns() **code for copying columns data along with header in another sheet name paste sheet**
Sheets("copysheet1").Columns(11).Copy Destination:=Sheets("paste").Columns(1)
Sheets("copysheet2").Range("A1:A20").Copy
Sheets("paste").Range("B1").PasteSpecial xlPastevalues
End Sub
Sub reconncilirecords() ** this function to reconcile records and color them green if matching**
Dim col1 As Range, col2 as Range,Prod1 as String, Prod2 as String
Set col1 = Sheets("paste").Columns("A")
Set col2 = Sheets("Paste").Columns("B")
lr = Sheets("paste").Columns("A:B").SpecialCells(xlCellTypeLastCell).Row
For r = 2 to lr
Prod1 = Cells(r, col1.Column).Value
Prod2 = Cells(r, col2.Column).Value
If Prod1 = Prod2 Then
Cells(r, col1.Column).Interior.Color = vbGreen
Cells(r, col2.Column).Interior.Color = vbGreen
Else
Cells(r, col1.Column).Interior.Color = vbRed
Cells(r, col2.Column).Interior.Color = vbRed
End If
Next r
End Sub
Sub Result() **function to display if marching or not matching with message box**
Dim wj as Wrokbook
Dim ws_data as worksheet
Dim rng_data as Range
Set wj = Activeworkbook
Set ws_data = ws.Sheets("paste")
Dim last_row as Long
last_row = ws_data.Cells(Rows.Count, "A").End(xlup).Row
Set rng_data = Range("A2:A" & last_row)
If rng_data.Interior.Color = RGB(0,255,0) then
Msgbox" details verfd and matching"
Else
Msbxo "Mismatch found"
End If
End Sub
is there any way to speed up this process as whenever i run reconcile data 2nd sub function macro is getting hanged. Is there any other way to dynamically copy from sheet1 and sheet2 and recocnile the data and apply message box to check for last row.
Building on my comment; this is a mock-up, so untested... should give an idea:
destWS.Columns(1).value = sourceWS1.columns(2).value
destWS.Columns(2).value = sourceWS2.columns(2).value
With destWS.Range("A1:B" & destLastRow)
.FormatConditions.Add Type:=xlExpression, Formula1:="=$A1=$B1"
With .FormatConditions(.FormatConditions.Count)
.SetFirstPriority
With .Interior
.Color = vbRed
End With
End With
End With
You will most likely want to use exact ranges, not columns, as it slows things down... a lot.

VBA Compare single row values and highlight the entire row if different

My code uses conditional formatting to look at the row values in Column A "Order ID", compares them, and then formats the cell if the row values are different. Instead of formatting the cell, how do I format the entire row based off of consecutive row values in Column A "Order ID" being different?
Said differently - if the value in Column A "Order ID" is different from the previous value in Column A "Order ID", I want to format the entire row that is different. My data is variable everyday so I need to use VBA!
Here is the output of my current code:
This is the desired outcome:
Here is the code
Sub Fulfillment()
'
' Fulfillment Macro
' Format the order number in column A as plum
Range("A2").Select
Range(Selection, Selection.End(xlDown)).Select
Selection.FormatConditions.Add Type:=xlExpression, Formula1:= _
"=MOD(SUM((A$2:A2<>A$1:A1)*1),2)=0"
Selection.FormatConditions(Selection.FormatConditions.Count).SetFirstPriority
With Selection.FormatConditions(1).Font.Color = RGB(0, 0, 0)
End With
With Selection.FormatConditions(1).Interior
.PatternColorIndex = xlAutomatic
.Color = RGB(221, 160, 221)
.TintAndShade = 0
End With
Selection.FormatConditions(1).StopIfTrue = False
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
Thank you! I do not necessarily need a conditional formatting solution, just a VBA solution that works dynamically.
A Different Flavor of Banded Rows
Option Explicit
Sub Fulfillment()
'
' Fulfillment Macro
' Format the order number in column A as plum
Const CriteriaColumn As Long = 1
Dim wb As Workbook: Set wb = ThisWorkbook
Dim ws As Worksheet: Set ws = wb.Worksheets("Sheet1") ' adjust
Dim rg As Range: Set rg = ws.Range("A1").CurrentRegion
Set rg = rg.Resize(rg.Rows.Count - 2).Offset(2) ' exclude first two rows
Application.ScreenUpdating = False
rg.Interior.Color = xlNone
Dim Col As Long: Col = 1
Dim cell As Range
Dim r As Long
For Each cell In rg.Columns(CriteriaColumn).Cells
r = r + 1
If cell.Value <> cell.Offset(-1).Value Then Col = Col Mod 2 + 1
If Col = 2 Then rg.Rows(r).Interior.Color = RGB(221, 160, 221)
Next cell
Application.ScreenUpdating = True
MsgBox "Fulfillment accomplished.", vbInformation
End Sub

VBA - How to insert a row and divide data into groups?

I use the code below to copy my data from one sheet to another.
Sub Copypastemeddata()
Dim wb As Workbook
Dim ws As Worksheet
Dim sourceCell As Range
Dim targetSheet As Worksheet
Dim StartRow As Integer
Application.ScreenUpdating = False
Application.CopyObjectsWithCells = False
Set wb = ThisWorkbook
Set ws = wb.Worksheets("Opgørsel")
Set sourceCell = ws.Range("D3") 'Cell with sheet names for copying to
StartRow = 1 'Destination row on targetSheet
With ws
Set targetSheet = wb.Worksheets(sourceCell.Text)
.Range("A1").CurrentRegion.Copy
targetSheet.Range("A" & StartRow).Insert Shift:=xlDown
targetSheet.Columns.AutoFit
End With
Application.CutCopyMode = 0
Application.ScreenUpdating = True
Application.CopyObjectsWithCells = True
End Sub
In the sheet I'm copying, i want to insert a row every time the value under cell "tykkelse [m]" is different and divide it under the same row if the value is the same for multiple copies.
Thanks.
below provides a possible solution:
Sub solved()
Set findfirst = Sheet1.Range("H:H").Find("tykkelse [m]")
currentvalue = findfirst.Offset(1, 0).Value
findfirst.Offset(-1, 0).EntireRow.Insert xlDown
With Range(Cells(findfirst.Row - 2, 1), Cells(findfirst.Row - 2, 14))
.Merge
.Value = currentvalue
End With
Set findfirst = Sheet1.Range("H:H").Find("tykkelse [m]")
Set findsecond = Sheet1.Range("H:H").FindNext(After:=findfirst)
Do While Intersect(findsecond, findfirst) Is Nothing
If findsecond.Offset(1, 0).Value <> currentvalue Then
currentvalue = findsecond.Offset(1, 0).Value
findsecond.Offset(-1, 0).EntireRow.Insert xlDown
With Range(Cells(findsecond.Row - 2, 1), Cells(findsecond.Row - 2, 14))
.Merge
.Value = currentvalue
End With
End If
Set findsecond = Sheet1.Range("H:H").FindNext(findsecond)
Loop
End Sub
First, we find the first occurrence of "tykkelse [m]":
Then we store the value associated to this occurrence, and insert the row above and merge (color and alignment still to be added)
We find first occurrence again, because it has shifted, and we need it for the check below. We loop over each occurrence in column H and check if we had them all by comparing it to the first occurrence.
For each occurrence, we check if the value underneath has changed; if so, we apply the same manipulations.

Variables in Conditional Formatting Formula1

I'm trying to use variables in the FormatCondition Formula1 property. The variables will be cell references. However, I can't get the syntax right. The two bits I'm having trouble with in the code below are: "=(C$3:J$10=""CM"")" and "=($C3:$J10=""RM"")".
The aim of this is to highlight a column with CM in a certain cell, and to highlight a row with RM in a certain cell. The number of columns and rows will increase and decrease, hence the use of variables.
Or if this isn't the right way or the best way, alternatives would be appreciated.
The code is:
Private Sub Workbook_Open()
Application.ScreenUpdating = False
'Rows
Dim iRowA As Integer, iRowB As Integer, iRowC As Integer
Dim iRowDataStart As Integer, iRowLast As Integer
'Columns
Dim iColX As Integer, iColY As Integer, iColZ As Integer
Dim iColDataStart As Integer, iColLast As Integer
'Ranges
Dim rAll As Range
Dim rRowB As Range, rColY As Range
Dim rRowMark As Range, rColMark As Range
'String
Dim sString As String
'Assign values, normally these would be variable values, not assigned
iRowA = 1: iRowB = 2: iRowC = 3
iRowDataStart = 4: iRowLast = 10
iColX = 1: iColY = 2: iColZ = 3
iColDataStart = 4: iColLast = 10
'Set ranges
Set rAll = Range(Cells(iRowA, iColX), Cells(iRowLast, iColLast))
Set rRowB = Range(Cells(iRowB, iColZ), Cells(iRowLast, iColLast))
Set rColY = Range(Cells(iRowC, iColY), Cells(iRowLast, iColLast))
Set rRowMark = Range(Cells(iRowC, iColZ), Cells(iRowLast, iColLast))
Set rColMark = Range(Cells(iRowC, iColZ), Cells(iRowLast, iColLast))
'Delete all CF currently in the worksheet
With rAll
.FormatConditions.Delete
End With
'Format column with Column Mark
sString = "=(C$3:J$10=""CM"")"
With rRowB
.FormatConditions.Add _
Type:=xlExpression, _
Formula1:=sString
.FormatConditions(.FormatConditions.Count).SetFirstPriority
With .FormatConditions(1)
.Interior.Color = RGB(196, 189, 151)
.StopIfTrue = False
End With
End With
'Format row with Row Mark
sString = "=($C3:$J10=""RM"")"
With rColY
.FormatConditions.Add _
Type:=xlExpression, _
Formula1:=sString
.FormatConditions(.FormatConditions.Count).SetFirstPriority
With .FormatConditions(1)
.Font.ColorIndex = 2
.Interior.Color = RGB(127, 127, 127)
.StopIfTrue = False
End With
End With
Range("A1").Select
Application.StatusBar = False
Application.CutCopyMode = False
End Sub
You just need to dynamically set your ranges by getting last row and column of your data where you can find many examples here like this one. Something like:
Dim r As Range
Dim lr As Long, lc As Long
Dim formula As String
With Sheet1 '~~> change to your actual sheet
lr = .Range("C" & .Rows.Count).End(xlUp).Row '~~> based on C, adjust to suit
lc = .Cells(3, .Columns.Count).End(xlToLeft).Column '~~> based on row 3
Set r = .Range(.Cells(3, 3), .Cells(lr, lc))
formula = "=(" & r.Address & "=""CM"")"
'~~> formatting code here
End With
Or you can try what I've posted here about Conditional Formatting which of course can be automated as I posted HERE and HERE. Something like:
formula = "=C3=""CM"""
[C3].FormatConditions.Add xlExpression, , formula
With [C3].FormatConditions(1)
.Interior.Color = RGB(196, 189, 151)
.ModifyAppliesToRange r
End With
HTH.

Excel autofit row height doesn't work on meged cells with word wrap

I'm programmatically inserting some text into merged cells in a row. I have Wrap Text set and want the row height to expand as necessary to accommodate multiple lines of text. I was programmatically applying AutoFit once the cells had been filled but that didn't work. I subsequently found a Knowledge Base article saying the AutoFit doesn't work for merged cells! I can try to compute the row height required to accommodate the number of lines of wrapping text. But I don't really want to climb into calculating character widths etc. Any ideas gratefully appreciated.
Question credit goes to David (I had the exact same question, just reposting here for posterity) source
I found a VB macro here that will simulate the autofit of any merged cells on the active sheet. Source credits parry from MrExcel.com
Sub AutoFitMergedCellRowHeight()
Dim CurrentRowHeight As Single, MergedCellRgWidth As Single
Dim CurrCell As Range
Dim ActiveCellWidth As Single, PossNewRowHeight As Single
Dim StartCell As Range, c As Range, MergeRng As Range, Cell As Range
Dim a() As String, isect As Range, i
'Take a note of current active cell
Set StartCell = ActiveCell
'Create an array of merged cell addresses that have wrapped text
For Each c In ActiveSheet.UsedRange
If c.MergeCells Then
With c.MergeArea
If .Rows.Count = 1 And .WrapText = True Then
If MergeRng Is Nothing Then
Set MergeRng = c.MergeArea
ReDim a(0)
a(0) = c.MergeArea.Address
Else
Set isect = Intersect(c, MergeRng)
If isect Is Nothing Then
Set MergeRng = Union(MergeRng, c.MergeArea)
ReDim Preserve a(UBound(a) + 1)
a(UBound(a)) = c.MergeArea.Address
End If
End If
End If
End With
End If
Next c
Application.ScreenUpdating = False
'Loop thru merged cells
For i = 0 To UBound(a)
Range(a(i)).Select
With ActiveCell.MergeArea
If .Rows.Count = 1 And .WrapText = True Then
'Application.ScreenUpdating = False
CurrentRowHeight = .RowHeight
ActiveCellWidth = ActiveCell.ColumnWidth
For Each CurrCell In Selection
MergedCellRgWidth = CurrCell.ColumnWidth + MergedCellRgWidth
Next
.MergeCells = False
.Cells(1).ColumnWidth = MergedCellRgWidth
.EntireRow.AutoFit
PossNewRowHeight = .RowHeight
.Cells(1).ColumnWidth = ActiveCellWidth
.MergeCells = True
.RowHeight = IIf(CurrentRowHeight > PossNewRowHeight, _
CurrentRowHeight, PossNewRowHeight)
End If
End With
MergedCellRgWidth = 0
Next i
StartCell.Select
Application.ScreenUpdating = True
'Clean up
Set CurrCell = Nothing
Set StartCell = Nothing
Set c = Nothing
Set MergeRng = Nothing
Set Cell = Nothing
End Sub

Resources