Excel PivotTable Conditional Formatting - excel

I have a pivot table in an Excel worksheet that contains the result of a query made to my database. I would like to format the information automatically based on every other data set.
The information contains 4 weeks' (1 month) worth of records for each employee sorted by an employee ID number. I would like to write a module so that it will highlight every other record (employee data set) with a different color. Is this even possible to do? Thanks for the help!

If you insist with solving your problem utilizing VBA here is an example. You'll need to specify start ranges. Please not that marking whole row will use more memory (increasing file size) so I would rather use example: range("A2:E2).select ....
Sub FormatEverySecondRow()
range("A2").EntireRow.Select
Do While ActiveCell.value <> ""
Selection.Interior.ColorIndex = 15
ActiveCell.offset(2, 0).EntireRow.Select
Loop
End Sub

use a helper column (K if I count the columns in your example)
insert into K2:
=IF(ISBlank(C2),K1,MOD(K1+1,2))
then use conditional formatting to highlight the row:
Note the formula does not have a $ sign before the 2 (i.e. $K2, not $K$2)

This might be useful to you:
Sub HighlightDifferentRows()
Dim wksht As Worksheet
Dim wkb As Workbook
Dim row As Range
Dim FloatColor As Long
FloatColor = RGB(100, 100, 100)
Set wbk = ThisWorkbook
Application.ScreenUpdating = False
For Each row In Sheets(1).UsedRange.Rows
row.Interior.Color = FloatColor
If row.Cells(1, 4).Value <> row.Cells(2, 4).Value Then
FloatColor = -FloatColor
End If
Next row
Application.ScreenUpdating = True
End Sub
It alternates row colors whenever a cell value is not the same as the one below it. Right now it is set to grayish colors but you could change it to something brighter if you wanted. You could put in your own logic to get whatever colors you wanted. Good Luck.

Related

How to alternate row color in a table when cell value changes?

I have a spreadsheet that brings in a table of data via Power Query.
Every time there is a refresh, the table length may change.
I need columns C and D to alternate highlight colors when the value is not the same as the previous row.
How the table should look each time it is refreshed through Power Query and the VBA code runs.
(1) Attempt with conditional formatting:
(Note: This will work correctly only if a value cannot appear later down that list).
Create a rule (or two rules, to be precise) based on a formula. According to your screenshot, I assume that your data starts at row 3 and you want to look at column C.
There is a rather easy formula that you can use to count the number of unique values of a list. The base formula was "borrowed" from ExcelJet and is =SUMPRODUCT(1/COUNTIF(data,data)). The trick now is that you look to the range from the beginning of the list to the actual row by using the range C$3:C3. If you copy the formula down, the start row remains while the end row is changed. Now simple put a IsOdd resp IsEven around the formula.
So the formula is =ISODD(SUMPRODUCT(1/COUNTIF(C$3:C3,C$3:C3))) for the "green" rows and =ISEVEN(SUMPRODUCT(1/COUNTIF(C$3:C3,C$3:C3))) for the yellow. Apply the rule to the range =$C$3:$C$1048576
However, I don't know if this conditional formatting will "survive" an update of the query.
(2)
Formatting with VBA is simple. The following code formats one column of an table (a table in VBA is the type ListObject. Pass the listobject and the column number as parameter:
Sub ColorRows(table As ListObject, columnNumber As Long)
Dim cell As Range, isOdd As Boolean
For Each cell In table.DataBodyRange.Columns(columnNumber).Cells
With cell
If .Offset(-1, 0) <> .Value Then isOdd = Not isOdd
' On a standard Office color scheme, 10 is kind of green and 8 is a dirty yellow
.Interior.ThemeColor = IIf(isOdd, 10, 8)
.Interior.TintAndShade = 0.8
End With
Next
End Sub
This is how the call could look like (adapt the sheet and the listObject to your needs):
Sub test()
ColorRows ThisWorkbook.Sheets(1).ListObjects(1), 3
End Sub
Now calling this code automatically is a different story and unfortunately rather complicated - if you want/need, try https://stackoverflow.com/search?q=vba+QueryTable+After+Refresh for some insights. An easy alternative is to trigger the formatting manually, eg by placing a button (or a shape) on your sheet that calls the code.
The VBA to apply the format condition for the alternating coloring would be:
Public Sub alternatingColorSizeAndKind(rg As Range)
Dim fc As FormatCondition
With rg.FormatConditions
.Delete
Set fc = .Add(xlExpression, , "=($C1=$C2)+($C2=$C3)")
fc.Interior.Color = 14348258
Set fc = .Add(xlExpression, , "=($C1<>$C2)")
fc.Interior.Color = 13431551
End With
End Sub
You have to pass the range of your table to this sub.
If you have a listobject/table then you call it like this:
Public Sub update()
Dim lo As ListObject
'>>> adjust the names to your needs
Set lo = ThisWorkbook.Worksheets("Sheet1").ListObjects("Pull_Data")
alternatingColorSizeAndKind lo.DataBodyRange
End Sub

In Excel, how do I have a line of code check what the value of a dropdown selection is. Then, how do I check that value vs another value

I am trying to create a macro that will first allow the user to easily transfer data to another sheet based on a dropdown list to select the month. I want the user to able to enter the date in the field I have created, then use buttons on the sheet to first select which month to paste though, then confirm the paste. I have twelve named ranges from Ref_Jan to Ref_Dec on a sheet named "DB - Ref Monthly" I am working on putting together the pieces but I'm stuck here with my test program:
Sub Button8_Click()
Dim MonthSelector As Range
Dim Ref_May As Range
If Range("MonthSelector") = Range("Ref_May") Then
Sheets("DB - Ref Current").Range("Ref_Current").Copy
Sheets("DB - Ref Monthly").Range("Ref_May").PasteSpecial xlPasteAll
Application.CutCopyMode = False
Application.ScreenUpdating = True
Else
End If
End Sub
My current plan is to use 12 if statements to refer to each month, as I already have the copy/paste portion of the code working in another sheet. If I am going about this all wrong I would not mind some guidance. Please let me know if I have been unclear and can provide additional information.
Use looping to iterate months then no need to duplicate a code logic.
Dim arrMonth As New Collection
Dim idx As Integer
Dim val As String
Call arrMonth.Add("Jan")
Call arrMonth.Add("Feb")
Call arrMonth.Add("Mar")
'..etc..
Call arrMonth.Add("Dec")
For idx = 1 To arrMonth.Count
val = arrMonth.Item(idx)
Call MsgBox(idx & "=" & val)
Next
Assuming Range("MonthSelector") is a cell that has a value from a list of months (Jan, Feb, Mar, etc.), and you've got corresponding named ranges Ref_Jan, Ref_Feb, Ref_Mar, etc., you could just do this:
Sub Button8_Click()
Sheets("DB - Ref Current").Range("Ref_Current").Copy
Sheets("DB - Ref Monthly").Range("Ref_" & Range("MonthSelector").Value).PasteSpecial xlPasteAll
Application.CutCopyMode = False
Application.ScreenUpdating = True
End Sub

How to extract records from a worksheet into a seperate worksheet using VLOOKUPS and IF's

Worksheet1:
Excel sheet
New
Worksheet 1 has licences with 6 columns of information - two being the start and end date.
I need a method of extracting all the records that are within 90 days before the expiry date- the idea being I want a separate alert page
I have done a IF statement that is on the end of the columns that just prints 1 if date is hits the alert criteria or 0 if not...The idea now in Worksheet2 I need some sort of VLOOKUP and IF to extract those records automatically.
How would I do this?
=IF(IFERROR(DATEDIF(TODAY(),H5,"d"),91)<90,1,0)
While use of Pivot table or VBA macro is recommended in such cases, if you absolutely need to use the formula then you may use the below trick.
You already have the Binary column. Now, add another column say Cumulative Binary that will sum all the 1's till the current row using a SumIf formula as shown in the screenshot below (it is fine if some numbers are repeated because of 0's)
The formula in I3 in my workbook is
=SUMIF(H$3:H3,1,H$3:H3)
and you may adjust it as per your needs.
Now, it is easy since each row has a unique number, we could use Vlookup or like I have done here i.e. use Offset function which simply matches the value in the "Lookup Column" to the value in "Cumulative Binary" column and returns the rows that match.
=IFERROR(OFFSET($F$2,MATCH(M3,$I$3:$I$9,0),0,1,2),"")
Please note that it is an array formula as I need to return multiple columns (2 here). So, I selected two columns N,O as shown in the screenshot wrote the formula and used Ctrl+Shift+Enter (instead of Enter). Then I simply dragged the formula down. You may want to adjust it as per your needs by including more columns.
If you can use VBA, you may write some code like this:
Option Explicit
Public Sub CopyCloseToExpiration()
Dim rngSource As Range: Set rngSource = ThisWorkbook.Worksheets("Sheet1").Cells(2, 1).Resize(LastRow(ThisWorkbook.Worksheets("Sheet1")) - 1, 9)
Dim rngDestinationTopLeft As Range: Set rngDestinationTopLeft = ThisWorkbook.Worksheets("Sheet2").Cells(LastRow(ThisWorkbook.Worksheets("Sheet2")) + 1, 1)
Dim datLimit As Date: datLimit = DateAdd("d", 90, Date)
CopyBeforeDate rngSource, rngDestinationTopLeft, datLimit
End Sub
Public Sub CopyBeforeDate(rngSource As Range, rngDestinationTopLeft As Range, datLimit As Date)
Dim lngOffset As Long: lngOffset = 0
Dim rngRow As Range: For Each rngRow In rngSource.Rows
If rngRow.Cells(1, 8).Value < datLimit Then
rngDestinationTopLeft.offset(lngOffset, 0).Resize(rngRow.Rows.Count, rngRow.Columns.Count).Value = rngRow.Value
lngOffset = lngOffset + 1
End If
Next
End Sub
Public Function LastRow(ewsSheet) As Long
With ewsSheet
Dim lngResult As Long: lngResult = .Cells(.Rows.Count, 1).End(xlUp).Row
End With
LastRow = lngResult
End Function
You have to put the above into a new Module, customize it (e.g. replace "Sheet1" with the name of you worksheet's actual name), and run it (You can place the caret on the sub CopyCloseToExpiration and hit F5 or place a button somewhere and call this function from its event handler).

VBA code to change font color for 3 columns based on the value of 1 column (multiple tables)

The situation:
I have about 2,600 tables in one .xlsx workbook, one table per tab. They're to be published online as PDFs but, first, I need to suppress frequencies and percentages in rows with frequencies smaller than 10. Mask formatting doesn't work with the crosslist option in SAS 9.3. So, I think the most efficient way is to change the font color in the appropriate cells to white. Unfortunately, conditional formatting doesn't work when you select multiple tabs. Using VBA seems like the best option, but I know very little about it.
Here's an example of the tables (I've hidden the rows for grades 4-7 for brevity):
Example: Original Table
The Goal:
Change the color of the font in cells with calculated values to white to mimic suppression. For example:
Example: "Suppressed" Table
Can anyone please point me in the right direction? I feel like this should be pretty straightforward but, every time I think that, it's the exact opposite. I saw a few similar questions, but none with answers that looked relevant to my issue.
Many thanks!!!!
Answering side-question about creating a temporary copy for export:
Sub CreateExportCopy()
Dim wb As Workbook, wbExport As Workbook, newPath As String
Set wb = Workbooks("DataTables.xlsx") '<< your (open) data file
newPath = wb.Path & "\ForPDF_" & wb.Name
'this will create a copy of the workbook in the same location,
' with the name prepended by "ForPFDF_"
wb.SaveCopyAs newPath
'open the copy
Set wbExport = Workbooks.Open(newPath)
'follow one of the other answers here to process the
' tables in wbExport, but use (eg)
' c.ClearContents
' instead of
' c.Font.Color = vbWhite
End Sub
Are they always in Column "C"? If not, you have to check that kind of stuff as well.
Does it always start at row 10?
As far as just looping through the sheets and values, if you want simple, this is about as simple as it gets:
Sub whiteout()
Dim c As Range, ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
For Each c In Range(ws.Range("C10"), ws.Range("C65000").End(xlUp))
If c.Value < 10 Then c.Font.Color = vbWhite
Next c
Next ws
End Sub
For each loops are pretty intuitive, but be aware that accessing and changing things like this in a loop can be pretty slow on a major scale.
doctorjay.
I worked on a dummy table of my own, based loosely on your dataset.
I would use a macro like this one:
Sub clean_lower_than_10()
Dim Sheet As Worksheet
For Each Sheet In ActiveWorkbook.Sheets
For Each Row In Sheet.UsedRange.Rows
'Columns where the frequency and percentage are: C,D -> 3,4
For Each Cell In Row.Cells
'Inside this condition, you should change the numbers for the column number that corresponds to the ones on your tables.
If Cell.Column = 3 Or Cell.Column = 4 Then
If Cell.Value < 10 Then
Cell.Font.ColorIndex = 2
End If
End If
Next
Next
Next
End Sub
The colorIndex = 2 means white color for the cell font.
This solution assumes that your percentage and frequency values are always on the same columns on every sheet.
If this is not the case, you'll have to work on the code to make it work, but it think this will be a good startpoint.
My table before executing macro:
My table after executing macro:
Notice that the value remains intact, but the font color has changed to white.
Hope it helps

How to hide columns which has all values less than a number in excel sheet?

I am newbie to the excel formulas.I have an excel sheet which has lets say 100 rows and 100 columns. columns have different values from 0 to 20. I want to hide the columns if all values of the column is less than a given number. Or in different way I want to display only those columns which any value is greater than a given number.
Throw the below code into a new module within your workbook. If you're not sure how to do that, then Google "How do I create a new module in my Excel VBA project" ...
Public Sub HideColumnsBasedOnCriteria()
Dim rngCells As Range, lngCol As Long, lngRow As Long, lngThreshold As Long
Dim bBelowThreshold As Boolean
Set rngCells = Selection
lngThreshold = InputBox("Enter a threshold amount ...", "Threshold Amount", 10)
Application.EnableEvents = False
Application.ScreenUpdating = False
With rngCells
For lngCol = 1 To .Columns.Count
bBelowThreshold = True
For lngRow = 1 To .Rows.Count
If .Cells(lngRow, lngCol) >= lngThreshold Then
bBelowThreshold = False
Exit For
End If
Next
If .Columns(lngCol).Hidden <> bBelowThreshold Then
.Columns(lngCol).Hidden = bBelowThreshold
End If
Next
End With
Application.ScreenUpdating = True
Application.EnableEvents = True
End Sub
... then select your cells (not the columns, but the range of data like shown below) and then run the macro.
If you don't know how to run the macro then Google "How do I execute a macro in Excel". If you don't have the developer tab, Google "How do I make the developer tab visible in Excel".
The columns with the number less than what you provide will then be hidden.
This is without error checking and the like but it will get you going. If you need to take the threshold amount from a cell on the worksheet, that is an easy addition.
I hope it works for you.
What you're asking is impossible: the result of an Excel-formula is a number of a piece of text, not the command for hiding a cell or a range of cells.
There is one interesting this, and that's conditional formatting: it does not allow you to hide an entire column, but it can, as mentioned by the name, modify the formatting of your cell, based on some condition. As a formatting, you might choose the background colour of your cells.
The difficult part here seems: how will you check if the values of an entire column are smaller than one value? This can be checked using a simple idea: every value is smaller than one particular value if the maximum of those values is smaller than that particular value, and here you have your conditional formatting, based on a formula: just base it on the formula =MAX(F1:F100)<=5, apply this conditional formatting on every cell of column F and apply a background colour accordingly.

Resources