Changing chart colors based on cell values - excel

I have a chart with 2 data series that reference cell values with conditional formatting to determine its color. I looked up a VBA code on the net to use on the chart to update the colors of the series based on the cell color, but when running the code nothing happens.
Anybody can help me with this?
Sub CellColorsToChart()
'Updateby Extendoffice
Dim xChart As Chart
Dim I As Long, J As Long
Dim xRowsOrCols As Long, xSCount As Long
Dim xRg As Range, xCell As Range
On Error Resume Next
Set xChart = ActiveSheet.ChartObjects("Chart 2").Chart
If xChart Is Nothing Then Exit Sub
xSCount = xChart.SeriesCollection.Count
For I = 1 To xSCount
J = 1
With xChart.SeriesCollection(I)
Set xRg = ActiveSheet.Range(Split(Split(.Formula, ",")(2), "!")(1))
If xSCount > 4 Then
xRowsOrCols = xRg.Columns.Count
Else
xRowsOrCols = xRg.Rows.Count
End If
For Each xCell In xRg
.Points(J).Format.Fill.ForeColor.RGB = ThisWorkbook.Colors(xCell.Interior.ColorIndex)
.Points(J).Format.Line.ForeColor.RGB = ThisWorkbook.Colors(xCell.Interior.ColorIndex)
J = J + 1
Next
End With
Next
End Sub

xCell.Interior references the cells applied color, not a conditional format.
If you are using Excel 2010+ then you should use .DisplayFormat to get the conditional format color.
Also, why bother with ThisWorkbook.Colorsand ColorIndex, just reference the color:
.Points(J).Format.Fill.ForeColor.RGB = xCell.DisplayFormat.Interior.Color
Also, after you set On Error Resume Next to trap an error on Set xChart =, you must reset the error handling
On Error Resume Next
Set xChart = ActiveSheet.ChartObjects("Chart 2").Chart
On Error GoTo 0 ' <~~ reset error handling
If xChart Is Nothing Then Exit Sub

Related

Colour bar charts; Not sure if I am collecting the correct range?

I am struggling with applying a previous bit of code I have used for the same process in a different workbook.
The process is that I have conditionally formatted a set of information (now on a different sheet) to change colour based on whether either "Lab" or "Office" is selected from the drop down list.
I then wanted (what I believe this code should do however I don't believe I have linked the series correctly) the graph which the information is in relation too to change the relevant data points to that colour, highlighting that on this floor you have selected "Office" or "Lab".
The code I am using starts here:
Sub CellColorsToChart()
Dim xChart As Chart
Dim I As Long, J As Long
Dim xRowsOrCols As Long, xSCount As Long
Dim xRg As Range, xCell As Range
On Error Resume Next
Set xChart = ActiveSheet.ChartObjects("Net Internal Area").Chart.Refresh
If xChart Is Nothing Then Exit Sub
xSCount = xChart.SeriesCollection.Count
For I = 1 To xSCount
J = 1
With xChart.SeriesCollection(I)
Set xRg = ActiveSheet.Range(Split(Split(.Formula, ",")(2), "!")(1))
If xSCount > 4 Then
xRowsOrCols = xRg.Columns.Count
Else
xRowsOrCols = xRg.Rows.Count
End If
For Each xCell In xRg
.Points(J).Format.Fill.ForeColor.RGB = ThisWorkbook.Colors(xCell.DisplayFormat.Interior.ColorIndex)
.Points(J).Format.Line.ForeColor.RGB = ThisWorkbook.Colors(xCell.DisplayFormat.Interior.ColorIndex)
J = J + 1
Next
End With
Next
End Sub
Document can be downloaded here: https://wetransfer.com/downloads/fbdb338026e7c42cc08193536270cdfc20211115102313/07937d
Any help or tips on how to understand and read this better would be amazing.
Best
Jack
Remove Refresh from this line Set xChart = ActiveSheet.ChartObjects("Net Internal Area").Chart.Refresh and refresh chart after If xChart Is Nothing Then Exit Sub
Option Explicit
Sub CellColorsToChart()
Dim xChart As Chart
Dim I As Long, J As Long, ix As Long
Dim xSCount As Long
Dim xRg As Range, xCell As Range
Set xChart = ActiveSheet.ChartObjects("Net Internal Area").Chart
If xChart Is Nothing Then Exit Sub
xChart.Refresh
xSCount = xChart.SeriesCollection.Count
For I = 1 To xSCount
With xChart.SeriesCollection(I)
J = 1
Set xRg = ActiveSheet.Range(Split(Split(.Formula, ",")(2), "!")(1))
For Each xCell In xRg
ix = xCell.DisplayFormat.Interior.ColorIndex
If ix >= 1 Then
.Points(J).Format.Fill.ForeColor.RGB = ThisWorkbook.Colors(ix)
.Points(J).Format.Line.ForeColor.RGB = ThisWorkbook.Colors(ix)
End If
J = J + 1
Next
End With
Next
End Sub

excel vlookup output with colored cell

I am trying to do a vlookup on a colored cell and return the output with background color. The value is getting returned but the background color is missing. I have tried in the following way. Please note that I am using Microsoft 365.
VBA Code:
Sub Worksheet_Change(ByVal Target As Range)
Dim I As Long
Dim xKeys As Long
Dim xDicStr As String
On Error Resume Next
Application.ScreenUpdating = False
xKeys = UBound(xDic.Keys)
If xKeys >= 0 Then
For I = 0 To UBound(xDic.Keys)
xDicStr = xDic.Items(I)
If xDicStr <> "" Then
Range(xDic.Keys(I)).Interior.Color = _
Range(xDic.Items(I)).Interior.Color
Else
Range(xDic.Keys(I)).Interior.Color = xlNone
End If
Next
Set xDic = Nothing
End If
Application.ScreenUpdating = True
End Sub
Added the following module:
Public xDic As New Dictionary
Function LookupKeepColor (ByRef FndValue, ByRef LookupRng As Range, ByRef xCol As Long)
Dim xFindCell As Range
On Error Resume Next
Set xFindCell = LookupRng.Find(FndValue, , xlValues, xlWhole)
If xFindCell Is Nothing Then
LookupKeepColor = ""
xDic.Add Application.Caller.Address, ""
Else
LookupKeepColor = xFindCell.Offset(0, xCol - 1).Value
xDic.Add Application.Caller.Address, xFindCell.Offset(0, xCol - 1).Address
End If
End Function
Checked the Microsoft Script Runtime box in the References – VBAProject dialog box.
Used the following formula:
LOOKUPKEEPCOLOR(D3,Sheet1!$BS$6:Sheet1!$BT$13,2)

Passing a dynamic range to charts

I want to check the status of a sheet and when changed automatically run some calculations. I also wish refresh a graph with the new data from that sheet.
I used the Worksheet_Change function. It calls the sub with the calculations and calls the sub that contains the chart modification code. They run as planned with one exception. The range that gets passed to the Chrt1 sub (responsible for the chart functionality) does not get updated on the graph once it has been called out for the first time.
I'm aware that this can be overcome with Excel built-in tables function but I'd like to code this simple routine in anyways.
The Worksheet_Change function:
Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
AutoChangeTest
Application.EnableEvents = True
End Sub
The main module code:
Sub AutoChangeTest()
Dim s1 As Worksheet, s2 As Worksheet
Dim i As Integer, j As Integer, lrow As Integer, lrow2 As Integer
Set s1 = Sheets("Arkusz3")
On Error GoTo Err1
lrow = s1.Cells(s1.Rows.Count, 1).End(xlUp).Row
For i = 1 To lrow
s1.Cells(i, 2) = s1.Cells(i, 1) * 2
Next
Call Chrt1(Range(s1.Cells(1, 1), s1.Cells(lrow, 2)), s1)
Err1:
If Not IsNumeric(s1.Cells(i, 1)) Then
s1.Cells(i, 1).Activate
End If
End Sub
Sub Chrt1(r1 As Range, s1 As Worksheet)
Dim c1 As Shape
Dim s As Worksheet
Dim cht As ChartObject
Dim i As Integer
i = 0
Set r = r1
Set s = s1
For Each cht In s.ChartObjects
i = i + 1
Next
If i = 0 Then
Set c1 = s.Shapes.AddChart
End If
c1.Chart.SetSourceData (r)
End Sub
Some suggestions in the code below:
Sub AutoChangeTest()
Dim ws As Worksheet 'avoid variable names with 1/l - too unclear
Dim i As Long, lrow As Long 'always use long over integer
Set ws = ThisWorkbook.Worksheets("Arkusz3")
lrow = ws.Cells(ws.Rows.Count, 1).End(xlUp).row
On Error GoTo exitHere
Application.EnableEvents = False 'don't re-trigger this sub...
For i = 1 To lrow
With ws.Cells(i, 1)
'easier to test than to trap an error if non-numeric
If IsNumeric(.Value) Then
ws.Cells(i, 2) = .Value * 2
Else
ws.Select
.Select
MsgBox "Non-numeric value found!"
GoTo exitHere 'acceptable use of Goto I think
End If
End With
Next
'don't think you need a separate method for this...
If ws.ChartObjects.Count = 0 Then ws.Shapes.AddChart 'no need to loop for a count
'assuming there will only be one chart...
ws.ChartObjects(1).Chart.SetSourceData ws.Range(ws.Cells(1, 1), ws.Cells(lrow, 2))
exitHere:
If Err.Number <> 0 Then Debug.Print Err.Description
Application.EnableEvents = True
End Sub
In your Chrt1 procedure, this bit
For Each cht In s.ChartObjects
i = i + 1
Next
If i = 0 Then
Set c1 = s.Shapes.AddChart
End If
can be replaced by the following:
If s.ChartObjects.Count = 0 Then
Set c1 = s.Shapes.AddChart
End If
But what is c1 if you don't have to add a chart? You haven't defined it, and the On Error means you never find out that it's broken.
Assuming you want the last chart object to be the one that is changed:
If s.ChartObjects.Count = 0 Then
Set c1 = s.Shapes.AddChart
Else
Set c1 = s.ChartObjects(s.ChartObjects.Count)
End If
And you should declare c1 as a ChartObject.
Finally, remove the parentheses around r in this line:
c1.Chart.SetSourceData r
Thank you all for support. The basic code that works is shown below. It isn't the best looking but it does the job.
Sub Chrt1(r1 As Range, s1 As Worksheet)
Dim c1 As Shape
Dim s As Worksheet
Dim cht As ChartObject
Dim i As Integer
i = 0
Set r = r1
Set s = s1
For Each cht In s.ChartObjects
i = i + 1
Next
If i = 0 Then
Set c1 = s.Shapes.AddChart
End If
Set cht = s.ChartObjects(1)
cht.Chart.SetSourceData Source:=r
End Sub

What is the Fastest Way to Find the First Formula in an Excel Range with VBA?

Is there any quicker method than using a for loop to find the first instance of a formula in a cell?
For Each dc In .Worksheets("testWS").Range(searchRange)
If dc.hasFormula() = True Then
formulaRow = Split(dc.Address, "$")(2)
formula = dc.formula
Exit For
End If
Next
No loop needed - use Range.SpecialCells. Include error handling since there may be no cells with formulas.
On Error Resume Next
Dim formulaRng As Range
Set formulaRng = .Worksheets("testWS").Range(searchRange).SpecialCells(xlCellTypeFormulas)
On Error GoTo 0
If Not formulaRng Is Nothing Then
Debug.Print formulaRng.Cells(1).Row
Debug.Print formulaRng.Cells(1).Formula
End If
Function FindFirstFormulaRow(ByRef rng As Range) As Long
Dim arrFormulas As Variant
Set arrFormulas = rng.SpecialCells(xlCellTypeFormulas)
Set rng = arrFormulas
If Not rng Is Nothing Then
FindFirstFormulaRow = Split(rng.Cells(1).Address, "$")(2)
Set rng = rng.Cells(1)
End If
End Function`

Fixing chart- label colors in Stacked area chart using VBA excel

I am trying to create a dashboard that allows the user to opt for either Line or Stacked area chart. The color codes for each of the label(category) is already pre-decided. The code for chart formatting works fine for the Line chart. However, it doesn't when i opt for Stacked-Area chart visualization. Below is the code for Line chart:
Public Function ChartSeriesFormat()
Dim objDictChartColor As Object
Dim varChartColor As Variant
Dim rngChartColor As Range
Dim objSalesChart As Chart
Dim rngTemp As Range
Dim strSeriesName As String
Dim lngStartRow As Long
Dim lngColor As Long
Dim lngItem As Long
' --> Assign objects
Set objSalesChart = shtOutput.ChartObjects("chtMarketShare").Chart
varChartColor = shtMapping.Range("rng_ChartColor").CurrentRegion
Set rngChartColor = shtMapping.Range("rng_ChartColor").CurrentRegion
Set objDictChartColor = CreateObject("Scripting.Dictionary")
For lngItem = 1 To UBound(varChartColor, 1)
If Not objDictChartColor.exists(LCase(varChartColor(lngItem, 1))) Then
objDictChartColor.Add LCase(varChartColor(lngItem, 1)), rngChartColor.Cells(lngItem, 1).Interior.Color
End If
Next lngItem
lngStartRow = shtOutput.Range("rng_OutputDB1").CurrentRegion.Rows.Count
For lngItem = 1 To objSalesChart.SeriesCollection.Count
With objSalesChart
'Make all the lines in the series xlcontinous
.SeriesCollection(lngItem).Border.LineStyle = xlContinuous
strSeriesName = LCase(.SeriesCollection(lngItem).Name)
lngColor = objDictChartColor.Item(strSeriesName)
.SeriesCollection(lngItem).Border.Color = lngColor
End With
Next
On Error Resume Next
With shtOutput.Range("rng_OutputDB2")
If .Offset(1).Value <> "" Then
Set rngTemp = .CurrentRegion.SpecialCells(xlCellTypeVisible)
End If
End With
If Err.Number <> 0 Then
Err.Clear: On Error GoTo 0: On Error GoTo -1
GoTo ClearMemory
End If
Err.Clear: On Error GoTo 0: On Error GoTo -1
For lngItem = lngStartRow To objSalesChart.SeriesCollection.Count
With objSalesChart
'Make all the lines in the series xlcontinous
.SeriesCollection(lngItem).Border.Color = objSalesChart.SeriesCollection(lngItem - (lngStartRow - 1)).Border.Color
.SeriesCollection(lngItem).Border.LineStyle = xlDot
End With
Next
ClearMemory:
End Function
The option to choose "Stacked-Area" chart was added later. Any help?

Resources