Modify VBA To Account For Conditional Formatting - excel

I'm attempting to use a COUNTIF-like function in Excel 2016 to total up a series of cells by their background color... 3 different colors (green, yellow, red) representing 3 different 'states' (first largest, second largest, third largest). I managed to get it working by using this VBA coding:
Function Countcolour(rng As Range, colour As Range) As Long
Dim c As Range
Application.Volatile
For Each c In rng
If c.Interior.ColorIndex = colour.Interior.ColorIndex Then
Countcolour = Countcolour + 1
End If
Next
End Function
However, this particular code doesn't take into account conditional formatting.
So for example, I try to conditionally format a set of data to highlight its first largest value green, second largest yellow, third largest red. I use this VBA function in another block to get a count of all the green highlights. However, it doesn't pick up on the background color of the cell because of the conditional formatting.
I'm sure I'm missing something obvious... I feel like the first part of the If condition should be some form of c.FormatCondition.Interior, but I've tried variations on the theme with no success.
Thanks in advance for any help that can be provided!

This is something many people try to do including me.
There are some useful codes on the internet like http://www.cpearson.com/excel/CFColors.htm
but after searching a lot I found only ONE with the answer
get conditional formatted color with vba in excel and it works!
The solution is easy:
you can use
.cells(1,1).displayformat.interior.color
or
.cells(1,1).displayformat.interior.colorIndex
Example:
Function CountColor(ByRef rng As Range, ByRef color As Long) As Variant
Dim total: total = 0
If (Not (rng Is Nothing)) Then
Dim element As Variant
For Each element In rng
total = total - (element.DisplayFormat.Interior.color = color) ' MINUS because TRUE evaluates to -1
Next element
End If
CountColor = total
End Function
Sub test_countColors()
With Sheet1
Dim rng As Range
Dim color As Long
Dim total As Long
Set rng = Range(.Cells(1, 1), .Cells(3500, 55)) ' Or anay other range
color = 8438015 ' Or any other color
total = CountColor(rng, color)
MsgBox "Total= " & total
End With
End Sub

Related

How to count color filled cells (regardless of text or blank) in excel?

I am trying to count the number of cells in a specific column that are filled with a specific color, as there can be multiple colors within one column. These cells can be empty or filled with text, and the excel guides I've found online aren't helping much as they can only count one or the other.
I found a VBA guide which suggested this code:
Function ColorCount(ColorCell As Range, DataRange As Range)
Dim Data_Range As Range
Dim Cell_Color As Long
Cell_Color = ColorCell.Interior.ColorIndex
For Each Data_Range In DataRange
If Data_Range.Interior.ColorIndex = Cell_Color Then
ColorCount = ColorCount + 1
End If
Next Data_Range
End Function
However, when I input this code and ran the =ColorCount function, every cell with any type of color was counted. Is there something I am doing wrong here? The specific function syntax I was told to follow is =ColorCount("cell with specific color as example","range of cells to count").

assign a range to white cells (non color) excel

I have an attendance form. Cells A1-G1, which will get an X for present. I have it set up to calculate the attendance percentage. I also have it set up to change the calculation based on number of days eligible ie new person starts mid month, they would only have 15 days, changing the numerator. I have to manually change the range for the countif statement.
A1:G1 is the range
J1 is the area we'd put in for how many days eligible (this is for those who are not on the whole term)
I3 is the default days eligible (regular whole term)
=COUNTIF(A1:G1,"X")/(IF(J1="",I3,J1))
This works fine, I'd like to set it up to change the countif to only count the range that has white cells vs other colors. Change the A1:G1 to say C1:G1 if cells A1, B2 were red.
I can explain for if needed. I see lots on how to change the color of a cell, but not to act on a color in countif.
D
Excel doesn't have in-built functionality for handling colors within formulas. You need to use VBA. But a note of caution, the following UDF won't recalculate unless you manually refresh. The proposed solution also uses SUMPRODUCT instead of COUNTIF:
Public Function HasNoFill(ByVal rng As Range) As Boolean()
Dim temp() As Boolean
ReDim temp(1 To rng.Count)
Dim cell As Range
For Each cell In rng
Dim i As Long
i = i + 1
temp(i) = cell.Interior.Color = 16777215
Next
HasNoFill = temp
End Function

Counting cells based on their colour and other criteria

I'm working on some rostering functions in Excel, with the basis being that we have a limited number of people that will need to be rostered-on for work, covering shifts at multiple sites
When planning the rosters, we use a simple set of coloured cells to fill-in for when people are on dayshift, nightshift, not-rostered, annual leave, etc. Given that there are multiple sites we plan for I need to have a quick formula that checks whether that individual has been rostered-on for simultaneous shifts at multiple sites (obviously not possible), so we can easily identify when there is a conflict in the planning stage. The formula needs to return a TRUE, or value (eg. count >1 means more than one assignment for that person) so that I can use either conditional formatting or VBA to highlight a cell/the row and draw attention to the conflict
What I've tried doing is summing/counting cells that are coloured with a few VBA methods:
Function ISFILLED(MyCell As Range)
If MyCell.Interior.colorIndex > 0 Then
Result = True
Else
Result = False
End If
ISFILLED = Result
End Function
and/or:
Function ColorFunction(rColor As Range, rRange As Range, Optional SUM As Boolean)
Dim rCell As Range
Dim lCol As Long
Dim vResult
lCol = rColor.Interior.ColorIndex
If SUM = True Then
For Each rCell In rRange
If rCell.Interior.ColorIndex = lCol Then
vResult = WorksheetFunction.SUM(rCell, vResult)
End If
Next rCell
Else
For Each rCell In rRange
If rCell.Interior.ColorIndex = lCol Then
vResult = 1 + vResult
End If
Next rCell
End If
ColorFunction = vResult
End Function
These both work fine on their own but I'm unable to combine this with a SUMIFS/COUNTIFS style function to only count the number of cells that are coloured when that individual's name appears against that assignment.
If you have a look in the sample image from the roster, you can see that Joe Bloggs 4 has been assigned a shift at both Site 1 and Site 2 on the 21/05/2014. What I'm after is essentially to count number of coloured cells on row, if the individuals name matching the criteria is against those cells. For this example if would be
=COUNTIFS(C8:AQ8, "Joe Bloggs 4", C12:AQ12, *Cell is Coloured*)
Colour of the cell doesn't matter (hence the first function ISFILLED is better as i don't need a reference cell for the fill), as it's just a sense-check.
Appreciate any help/pointers, as it is, I'm stuck!
You won't be able to use SUMIFS and COUNTIFS for this. You need something along these lines:
Function IsFilledArr(rng As Range) As Variant
Dim i As Long, j As Long
Dim v As Variant
ReDim v(1 To rng.Rows.Count, 1 To rng.Columns.Count)
For i = 1 To rng.Rows.Count
For j = 1 To rng.Columns.Count
v(i, j) = rng.Cells(i, j).Interior.ColorIndex > 0
Next j
Next i
IsFilledArr = v
End Function
This UDF can be called as an array formula, i.e. select a range of cells, type the formula in the top-left cell (while the whole range is still selected), and then press Ctrl-Shift-Enter. Then you can operate on the returned array, e.g. SUM it.
Example usage:
where the -- double minus converts Boolean TRUE/FALSE values (which are not summable) into 1's and 0's (which are).
I'll let you adapt this to suit your particular requirements.
EDIT: You want more:
calculate the number of filled cells in column C, where there was an adjacent filled cell in column B - in this case C4 would be the only cell that met that criteria.
This formula will do the trick (entered as an array formula):
=SUM(IF(IsFilledArr(B2:B7)+IsFilledArr(C2:C7)>1,1))
Note the use of SUM(IF(...,1)) to mimic COUNT. That is the way to do it when you're dealing with array formulas.
Read more here: http://www.cpearson.com/excel/ArrayFormulas.aspx
You asked for help/pointers; this should hopefully be more than enough to get you unstuck. You can adapt this approach to meet whatever you exact needs are.

edit the program to sumif with visible cells in MS excel

i got some countifv thats counts visible and sumifsv which sum visible cells only ... i want sumif only visible using vba
Default Using SUMIFS on visible lines only
I have a large table, lots of rows and lots of columns that has material (Sand, stone, etc.) batched information. I wanted to be able to allow the user to use filters to select which data they want to view, then be able to review some summary information (totals by hour of the day, totals by material, etc.) on other sheets.
I had it working really well and fast using DSUM and/or SUBTOTAL, but these functions don't exclude non-visible (Filtered) lines in a list.
Using some previous posts I saw on this site, I was able to come up with something that works, but it is extremely slow.
I was hoping that more experienced folks could advise me on something that was faster.
What I need to do is to take a list of records on a sheet that contain up to 30 material columns of information (Target and Actual batch weight amounts.) I need to group each of these lines by material into a relative time bucket (12:00 AM to 12:59 AM, 1:00 AM to 1:59 AM, etc.) The user can of course select with Time Bucket they want to view
I am using the sumifs function with two critieria ( i.e. Time >=12:00 and Time < 1:00 ) to get the hourly buckets.
You can also see from this code that I have to count the number of lines for the data and each criteria value because I could not figure out how to set the range of "B" & "C" without counting. Since I am using a filter, I know that the ranges (from a row perspective) of A,B & C are the same, just the relative columns are different. I tried to use the offset function, (i.e. Range(B) = Range(A).Offset(-1,0).Select or B = A.offset(-1,0).Select but they failed for some reason, and no error messages either. I think I somehow turned the erroring off.
Anyway, long story, really could use some help. Here is the related code:
Function Vis(Rin As Range) As Range
'Returns the subset of Rin that is visible
Dim Cell As Range
'Application.Volatile
Set Vis = Nothing
For Each Cell In Rin
If Not (Cell.EntireRow.Hidden Or Cell.EntireColumn.Hidden) Then
If Vis Is Nothing Then
Set Vis = Cell
Else
Set Vis = Union(Vis, Cell)
End If
End If
Next Cell
End Function
Function SUMIFv(Rin As Range, CriteriaRange1 As Range, CriteriaValue1 As Variant, CriteriaRange2 As Range, CriteriaValue2 As Variant) As Long
'Same as Excel SUMIFS worksheet function, except does not count
'cells that are hidden
Dim A1() As Range
Dim B1() As Range
Dim C1() As Range
Dim Csum As Long
' First count up the number of ranges
Cnt = 0
For Each A In Vis(Rin).Areas
Cnt = Cnt + 1
Next A
ReDim A1(1 To Cnt)
ReDim B1(1 To Cnt)
ReDim C1(1 To Cnt)
CntA = 1
For Each A In Vis(Rin).Areas
Set A1(CntA) = A
CntA = CntA + 1
Next A
CntB = 1
For Each B In Vis(CriteriaRange1).Areas
Set B1(CntB) = B
CntB = CntB + 1
Next B
CntC = 1
For Each C In Vis(CriteriaRange2).Areas
Set C1(CntC) = C
CntC = CntC + 1
Next C
If CntA <> CntB Or CntB <> CntC Then
MsgBox ("Error in Sumifs Function: Counts from Ranges are not the same")
End If
Csum = 0
For Cnt = 1 To CntA - 1
Csum = Csum + WorksheetFunction.SumIfs(A1(Cnt), B1(Cnt), CriteriaValue1, C1(Cnt), CriteriaValue2)
Next
SUMIFv = Csum
End Function
((countifv visible cells only
If you are interested, here is a more general COUNTIF solution, and one that you can also apply to SUM and other functions that operate on ranges of cells.
This COUNTIFv UDF uses the worksheet function COUNTIF to count visible cells only, so the Condition argument works the same as with COUNTIF. So you can use it just as you would COUNTIF:
=COUNTIFv(A1:A100,1)
Note that it uses a helper function (Vis) that returns the disjoint range of visible cells in a given range. This can be used with other worksheet functions to cause them to operate only on the visible cells. For example,
=SUM(Vis(A1:A100))
yields the sum of the visible cells in A1:A100. The reason why this approach of using Vis directly in the argument list does not work with COUNTIF is that COUNTIF will not accept a disjoint range as an input, whereas SUM will.
Here's the UDF code:
Function Vis(Rin As Range) As Range
'Returns the subset of Rin that is visible
Dim Cell As Range
Application.Volatile
Set Vis = Nothing
For Each Cell In Rin
If Not (Cell.EntireRow.Hidden Or Cell.EntireColumn.Hidden) Then
If Vis Is Nothing Then
Set Vis = Cell
Else
Set Vis = Union(Vis, Cell)
End If
End If
Next Cell
End Function
Function COUNTIFv(Rin As Range, Condition As Variant) As Long
'Same as Excel COUNTIF worksheet function, except does not count
'cells that are hidden
Dim A As Range
Dim Csum As Long
Csum = 0
For Each A In Vis(Rin).Areas
Csum = Csum + WorksheetFunction.CountIf(A, Condition)
Next A
COUNTIFv = Csum
End Function ))
this both are countif and sumifs with visible cells but i need sumif not sumifs please edit the 2nd code and compile and post the correct program :)
I don't think this is correct...
......................................using DSUM and/or SUBTOTAL, but
these functions don't exclude non-visible (Filtered) lines in a list.
The behaviour for SUBTOTAL is different for "filtered" and "hidden" rows.
This is from the excel help:
For the function_num constants from 1 to 11, the SUBTOTAL function
includes the values of rows hidden by the Hide Rows command under the
Hide & Unhide submenu of the Format command in the Cells group on the
Home tab in the Excel desktop application. Use these constants when
you want to subtotal hidden and nonhidden numbers in a list. For the
function_Num constants from 101 to 111, the SUBTOTAL function ignores
values of rows hidden by the Hide Rows command. Use these constants
when you want to subtotal only nonhidden numbers in a list.
The SUBTOTAL function ignores any rows that are not included in the
result of a filter, no matter which function_num value you use.

Count a list of cells with the same background color

Each cell contains some text and a background color. So I have some cells that are blue and some that are red. What function do I use to count the number of red cells?
I have tried =COUNTIF(D3:D9,CELL("color",D3)) with no success (Where D3 is red).
Excel has no way of gathering that attribute with it's built-in functions. If you're willing to use some VB, all your color-related questions are answered here:
http://www.cpearson.com/excel/colors.aspx
Example form the site:
The SumColor function is a color-based
analog of both the SUM and SUMIF
function. It allows you to specify
separate ranges for the range whose
color indexes are to be examined and
the range of cells whose values are to
be summed. If these two ranges are the
same, the function sums the cells
whose color matches the specified
value. For example, the following
formula sums the values in B11:B17
whose fill color is red.
=SUMCOLOR(B11:B17,B11:B17,3,FALSE)
The worksheet formula, =CELL("color",D3) returns 1 if the cell is formatted with color for negative values (else returns 0).
You can solve this with a bit of VBA. Insert this into a VBA code module:
Function CellColor(xlRange As Excel.Range)
CellColor = xlRange.Cells(1, 1).Interior.ColorIndex
End Function
Then use the function =CellColor(D3) to display the .ColorIndex of D3
I just created this and it looks easier. You get these 2 functions:
=GetColorIndex(E5) <- returns color number for the cell
from (cell)
=CountColorIndexInRange(C7:C24,14) <- returns count of cells C7:C24 with color 14
from (range of cells, color number you want to count)
example shows percent of cells with color 14
=ROUND(CountColorIndexInRange(C7:C24,14)/18, 4 )
Create these 2 VBA functions in a Module (hit Alt-F11)
open + folders. double-click on Module1
Just paste this text below in, then close the module window (it must save it then):
Function GetColorIndex(Cell As Range)
GetColorIndex = Cell.Interior.ColorIndex
End Function
Function CountColorIndexInRange(Rng As Range, TestColor As Long)
Dim cnt
Dim cl As Range
cnt = 0
For Each cl In Rng
If GetColorIndex(cl) = TestColor Then
Rem Debug.Print ">" & TestColor & "<"
cnt = cnt + 1
End If
Next
CountColorIndexInRange = cnt
End Function
I was needed to solve absolutely the same task. I have divided visually the table using different background colors for different parts. Googling the Internet I've found this page https://support.microsoft.com/kb/2815384. Unfortunately it doesn't solve the issue because ColorIndex refers to some unpredictable value, so if some cells have nuances of one color (for example different values of brightness of the color), the suggested function counts them. The solution below is my fix:
Function CountBgColor(range As range, criteria As range) As Long
Dim cell As range
Dim color As Long
color = criteria.Interior.color
For Each cell In range
If cell.Interior.color = color Then
CountBgColor = CountBgColor + 1
End If
Next cell
End Function
Yes VBA is the way to go.
But, if you don't need to have a cell with formula that auto-counts/updates the number of cells with a particular colour, an alternative is simply to use the 'Find and Replace' function and format the cell to have the appropriate colour fill.
Hitting 'Find All' will give you the total number of cells found at the bottom left of the dialogue box.
This becomes especially useful if your search range is massive. The VBA script will be very slow but the 'Find and Replace' function will still be very quick.

Resources