Is there a way to list chart numbers based on position in the spreadsheet? (Not in sorted order?) - excel

The following macro lists all the chart numbers of by worksheet but it order them and this is not how the charts appear in the sheet.
Sub ListChartNames()
Dim Cht As ChartObject
Dim i As Integer
i = 1
For Each Cht In ActiveSheet.ChartObjects
Cells(i, 1) = Cht.Chart.Name
i = i + 1
Next Cht
End Sub
For example, I have a chart in E6:L17 (let's call this one Chart 1) and another in N6:U17 (let's call this one Chart 11).
Then, I move down to two charts in E19:L30 (let's call this one Chart 400) and another in N19:U30 (let's call this one Chart 2).
Then, I move down to two charts in E32:L43 (let's call this one Chart 3) and another in N32:U43 (let's call this one Chart 12)
Then, I move down to only 1 chart in E45:L56 (let's call this one Chart 13)
Then, I back to two charts in E58:L69 and another in N58:U69 (let's call these Chart 15 and Chart 16)
and so on.....
The above charts are all in columns E through U. But then there is another set in columns Y through AO in same patter and again in AS through BI, etc.
I have like 500 charts and I'd like a macro to list them starting in the first set of columns (E through L) but list them from top to bottom, let to right.
So, the results based on the above would be for columns F through U
Chart 1
Chart 11
Chart 400
Chart 2
Chart 3
Chart 12
Chart 13
Chart 15
Chart 16
The macro above lists the charts in a sorted order which is not what I need.
This also doesn't answer the question: Select chart object based on position in sheet (VBA)

Does this give you what you need?
Sub list_charts_in_top_left_to_bottom_right()
Dim ws As Worksheet, outputsh As Worksheet, last_cell As Range, oChartObj As Object
Set ws = ThisWorkbook.Sheets("SheetWithChartsOnIt")
Set outputsh = ThisWorkbook.Sheets("SheetToWriteTo")
outputsh.Range("A:A").ClearContents
outputsh.Range("A1") = "Output:"
If ws.ChartObjects.Count = 0 Then
outputsh.Range("A2") = "No charts found"
Exit Sub
End If
Debug.Print "Charts found: " & ws.ChartObjects.Count
Set last_cell = ws.Range("A1")
'find bounds of range by expanding last_cell with each chart
For Each oChartObj In ws.ChartObjects
With oChartObj
If .TopLeftCell.Row > last_cell.Row Then Set last_cell = ws.Cells(.TopLeftCell.Row, last_cell.Column)
If .TopLeftCell.Column > last_cell.Column Then Set last_cell = ws.Cells(last_cell.Row, .TopLeftCell.Column)
End With
Next
Debug.Print "Bounds of range: $A$1:" & last_cell.Address
Dim area_to_examine As Range
For col = 5 To last_cell.Column Step 21 'start with column 5 (E) and then jump 21 columns at a time
Set area_to_examine = Range(Columns(col), Columns(col + 17))
Debug.Print "Examining: " & area_to_examine.Address
For Each rw In Intersect(area_to_examine, ws.Range("A1", last_cell.Address).Rows)
For Each cl In rw.Cells
For Each oChartObj In ws.ChartObjects
With oChartObj
If .TopLeftCell.Row = cl.Row And .TopLeftCell.Column = cl.Column Then
outputsh.Cells(outputsh.Rows.Count, "A").End(xlUp).Offset(1) = .Name
Debug.Print .Name
End If
End With
Next
Next
Next
Next
End Sub

This is an alternative method. It's still not using a sort algo, but uses a workaround which (does waste a little time but) should be massively quicker than scanning every cell in the sheet:
Sub list_charts_in_top_left_to_bottom_right_v2()
Dim ws As Worksheet, outputsh As Worksheet, chartCount As Long, x As Long, y As Long, maxZ As Long
Set ws = ThisWorkbook.Sheets("SheetWithChartsOnIt")
Set outputsh = ThisWorkbook.Sheets("SheetToWriteTo")
outputsh.Range("A:A").ClearContents
outputsh.Range("A1").Value = "Chart"
chartCount = ws.ChartObjects.Count
ReDim arrChartlist(chartCount, 1)
If chartCount = 0 Then
outputsh.Range("A2") = "No charts found"
Exit Sub
End If
maxZ = 0
For x = 0 To chartCount - 1
With ws.ChartObjects(x + 1)
arrChartlist(x, 0) = .Name
arrChartlist(x, 1) = (((.TopLeftCell.Column - 2) \ 19) * chartCount * chartCount) + (.TopLeftCell.Column * chartCount) + .TopLeftCell.Row
If maxZ < arrChartlist(x, 1) Then maxZ = arrChartlist(x, 1)
End With
Next
For x = 0 To maxZ
For y = 0 To chartCount - 1
If x = arrChartlist(y, 1) Then
outputsh.Cells(outputsh.Rows.Count, "A").End(xlUp).Offset(1).Value = arrChartlist(y, 0)
End If
Next
Next
End Sub

Related

Excel VBA Chart counting and formatting

I'd like to create a macro that counts the number of charts within a given range, then performs certain actions depending on the number counted. I know activesheet.chartobjects.count would count across the whole sheet, how would I modify to count within a range?
Here's the skeleton of my code.
Sub chrt_chck()
Dim rng As Range
Dim x As Long
Set rng = Range("A1:F10")
x = ActiveSheet.rng.ChartObjects.Count
If x > 1 Then
'select and delete all charts in range
End If
If x = 1 Then
'select that chart and update format
Else
'create chart and set format
End If
End Sub
Please, try the next way:
Sub chrt_chck()
Dim rng As Range, chO As ChartObject, x As Long, arrChO() As ChartObject, k As Long, El
Set rng = Range("B2:D15") ' Range("A1:F10")
ReDim arrChO(ActiveSheet.ChartObjects.count - 1)
For Each chO In ActiveSheet.ChartObjects
If Not Intersect(chO.TopLeftCell, rng) Is Nothing Then
x = x + 1
Set arrChO(k) = chO: k = k + 1
End If
Next
If x > 1 Then
'select and delete all charts in range
For Each El In arrChO
Debug.Print El.name
El.Delete
Next
End If
If x = 1 Then
'select that chart and update format
With arrChO(0)
.Select
Debug.Print .name
'do wahtever needed with the chart...
End With
Else
'create chart and set format
End If
End Sub
It counts all chart objects having their Top Left corner inside the rng Range.

how do i offset all the charts in the same worksheet in VBA?

Currently, all my charts are cramped together in the same spot in the same worksheet after running my code. So to view them i have to manually drag and move them to another spot. So is there a way such that i can place all the charts in a orderly manner as shown in expected output? If it is really impossible to do something like this, i am ok with offsetting the graph for every 20 cells even though it is abit inconvenient for viewing but still i attempted to do it but fail to make it happen when i include code with current output with the offsetting code.
Current output(looks like there is 1 chart but all the charts are in the same spot)
Below is the code for my current output
Sub plotgraphs()
'Call meangraph
Call sigmagraph
End Sub
Private Sub sigmagraph()
Dim i As Long, c As Long
Dim shp As Shape
Dim Cht As chart, co As Shape
Dim rngDB As Range, rngX As Range, rngY As Range
Dim Srs As Series
Dim ws As Worksheet
Set ws = Sheets("Data")
Set rngDB = ws.Range("A1").CurrentRegion
Set rngX = rngDB.Columns(1)
Set rngY = rngDB.Columns(4)
Do While Application.CountA(rngY) > 0
Set co = Worksheets("meangraphs").Shapes.AddChart
Set Cht = co.chart
With Cht
.ChartType = xlXYScatter
'remove any data which might have been
' picked up when adding the chart
Do While .SeriesCollection.Count > 0
.SeriesCollection(1).Delete
Loop
'add the data
With .SeriesCollection.NewSeries()
.XValues = rngX.Value
.Values = rngY.Value
End With
'formatting...
With Cht.Axes(xlValue)
.MinimumScale = 0
.MaximumScale = 0.5
.TickLabels.NumberFormat = "0.00E+00"
End With
Cht.Axes(xlCategory, xlPrimary).HasTitle = True
Cht.Axes(xlValue, xlPrimary).HasTitle = True
End With
Set rngY = rngY.Offset(0, 2) 'next y values
Loop
Code for offsetting chart for every 20 cells (fail to make it happen)
Dim OutSht As Worksheet
'
Dim PlaceInRange As Range
Set OutSht = ActiveWorkbook.Sheets("sigmagraphs") '<~~ Output sheet
Set PlaceInRange = OutSht.Range("B2:J21") '<~~ Output location
'
' To place charts at a distance between them
For Each chart In Sheets("sigmagraphs").ChartObjects
' OutSht.Paste PlaceInRange
' Code below changes the range itself to something 20 rows below
Set PlaceInRange = PlaceInRange.Offset(20, 0)
Next chart
Expected output
What you are looking for is the .Left and .Top properties of the Shape containing the Chart.
For example, a macro that would setup your charts into a 2-column grid would look like this:
Sub SetupChartsIntoGrid()
Const TopAnchor As Long = 50
Const LeftAnchor As Long = 50
Const HorizontalSpacing As Long = 10
Const VerticalSpacing As Long = 10
Const ChartHeight As Long = 211
Const ChartWidth As Long = 360
Dim shp As Shape
For Each shp In ActiveSheet.Shapes
If shp.Type = msoChart Then
Dim Counter As Long
Counter = Counter + 1
With shp
.Top = TopAnchor + (WorksheetFunction.RoundUp(Counter / 2, 0) - 1) * (VerticalSpacing + ChartHeight)
.Left = LeftAnchor + ((Counter + 1) Mod 2) * (HorizontalSpacing + ChartWidth)
End With
End If
Next
End Sub

Create multiple line charts using Macro in Excel

I have created a macro which creates line chart for each row. Below is the code.
The data is in following format:
Format in which I have the data:
Sub createChartWithLoop()
Dim wks As Worksheet
Set wks = Worksheets("Sheet1")
Dim chrt As Chart
Set chrt = wks.Shapes.AddChart.Chart
Dim chartRange As Range
Set chartRange = wks.Range("A1:A4")
With chrt
.ChartType = xlLine
.SetSourceData Source:=Range(wks.Range("A" & chartRange.Row & ":D" & chartRange.Row).Address)
For i = chartRange.Row + 1 To chartRange.Rows.Count
.SeriesCollection.NewSeries
.SeriesCollection(i).Name = wks.Cells(i, 1)
.SeriesCollection(i).Values = wks.Range("B" & i & ":D" & i)
Next i
End With
End Sub
However, now I have a little different requirement. Assume I have 30 rows same format.
Requirement: I have to consider the first 3 rows as 1 set. 2nd 3 rows as 2nd Set and so on. So here effective we will have 10 set (30 rows/3). Each set should give me a chart.
Right now, I'm getting a chart with 3 lines (3 records). Above is my code. Can anyone help on the above request?
I wrote a procedure which will plot a stated number of charts each using a stated number of rows. Then I wrote a short procedure that shows how to have it create 10 charts with three rows each.
Here is the procedure to create nCharts charts, using nRows rows for each:
Sub CreateChartWithLoop(nCharts As Long, nRows As Long)
Dim wks As Worksheet
Set wks = ActiveSheet
Dim DataRange As Range
Set DataRange = ActiveSheet.UsedRange
Dim iChart As Long
For iChart = 1 To nCharts
Dim cht As Chart
Set cht = wks.Shapes.AddChart(xlLine, DataRange.Width, DataRange.Rows(1 + (iChart - 1) * nRows).Top).Chart
Do Until cht.SeriesCollection.Count = 0
cht.SeriesCollection(1).Delete
Loop
Dim iRow As Long
For iRow = 1 To nRows
With cht.SeriesCollection.NewSeries
.Name = "=" & DataRange.Cells(iRow + (iChart - 1) * 3, 1).Address(, , , True)
.Values = DataRange.Rows(iRow + (iChart - 1) * 3).Offset(, 1).Resize(, DataRange.Columns.Count - 1)
End With
Next
cht.HasTitle = True
cht.ChartTitle.Text = "Chart " & iChart
Next
End Sub
Here's the procedure that calls the main procedure, telling it to make 10 charts with 3 rows each:
Sub Create10ChartsWith3RowsEach()
CreateChartWithLoop 10, 3
End Sub

Add series to chart

I use Holebase for work and it would be very useful for me if excel knew how to differentiate the start of a new series since the macro we have so far only displays one series by making a gap between series.
So the macro I'm trying to manipulate was taken from here and has already been adjusted since the previous one suited a purpose slightly different.
What I want is: Everytime I find a new BH on column A plot a distinct series with the values from column C and column D (x and y respectively) till the next BH on column A.
I managed to sort it out. So the macro first deletes all series inside the chart, second everytime time there is a new value / text on column A it displays the data shown on column C (X) and column D (Y).
No I have only one more problem to sort it out. The x range needs to have a minimum date since excel always adopts 1900 by default
Sub MakeCharts()
Dim sh As Worksheet
Dim rAllData As Range
Dim rChartData As Range
Dim cl As Range
Dim rwStart As Long, rwCnt As Long
Dim s As Series
Dim SourceRangeColor As Long
Set sh = ActiveSheet
sh.ChartObjects(1).Activate
'Set chrt = sh.ChartObjects(1)
For Each s In ActiveChart.SeriesCollection
s.Delete
Next s
With sh
' Get reference to all data
Set rAllData = .Range(.[A1], .[A1].End(xlDown)).Resize(, 4)
' Get reference to first cell in data range
rwStart = 2
Set cl = rAllData.Cells(rwStart, 1)
Do While cl <> ""
'Capture the first cell in the source range then trap the color
Set SourceRange = rAllData.Cells(rwStart, 5)
SourceRangeColor = SourceRange.Interior.Color
' cl points to first cell in a station data set
' Count rows in current data set
rwCnt = Application.WorksheetFunction. _
CountIfs(rAllData.Columns(1), cl.Value)
' Get reference to current data set range
Set rChartData = rAllData.Cells(rwStart, 1).Resize(rwCnt, 4)
'ActiveChart.SeriesCollection.Add _
'Source:=rChartData
With ActiveChart.SeriesCollection.NewSeries
.ChartType = xlXYScatterLines
.XValues = rChartData.Offset(, 2).Resize(, 1)
.Values = rChartData.Offset(, 3).Resize(, 1)
.Name = rAllData.Cells(rwStart, 1)
.MarkerBackgroundColor = SourceRangeColor
.MarkerForegroundColor = SourceRangeColor
'.Format.Line.ForeColor.RGB = SourceRangeColor (line colour for workbook 2007-2010)
'.Format.Line.BackColor.RGB = SourceRangeColor (line colour for workbook 2007-2010)
'.Format.Fill.ForeColor.RGB = SourceRangeColor (line colour for workbook 2007-2010)
.Interior.Color = SourceRangeColor
.Border.Color = SourceRangeColor
'.Axes(xlCategory, xlPrimary).CategoryType = xlTimeScale
'.Axes(xlCategory, xlPrimary).TickLabels.NumberFormat = "dd-mm-yyyy"
'.Axes(xlCategory, xlPrimary).MinimumScale = Application.Min.Range("C:C")
'.Axes(xlCategory, xlPrimary).MaximumScale = Application.Max.Range("C:C")
' Get next data set
rwStart = rwStart + rwCnt
Set cl = rAllData.Cells(rwStart, 1)
End With
Loop
End With
End Sub
Thanks
enter image description here

X Axis isn't charting properly

I have a macro that charts data for me. Everything about the macro works with 1 exception: I want to redesignate the x-axis labels. The macro does do this but it doesn't do it right. In some cases it frame shifts the categories, in others it labels a category completely wrong. The macro is supposed to chart the data by product ID (one chart per product ID) and then change the x-axis category to the label in column F on "Chart Data."
Thanks, in advance, for your help.
Below is the part of the macro that creates the charts and subsequently changes the x axis:
Sub MakeCharts()
Dim sh As Worksheet
Dim rAllData As Range
Dim rChartData As Range
Dim cl As Range
Dim rwStart As Long, rwCnt As Long
Dim chrt As Chart
Set sh = ActiveSheet
ActiveSheet.Range("a1").Select
With sh
' Get reference to all data
Set rAllData = .Range(.[A2], .[A2].End(xlDown)).Resize(, 5)
' Get reference to first cell in data range
rwStart = 1
Set cl = rAllData.Cells(rwStart, 1)
Do While cl <> ""
' cl points to first cell in a station data set
' Count rows in current data set
rwCnt = Application.WorksheetFunction. _
CountIfs(rAllData.Columns(1), cl.Value)
' Get reference to current data set range
Set rChartData = rAllData.Cells(rwStart, 1).Resize(rwCnt, 5)
' Create Chart next to data set
Set chrt = .Shapes.AddChart(xlLineMarkers, _
rChartData.Width, .Range(.[A2], cl).Height).Chart
With chrt
.SetSourceData Source:=rChartData.Offset(0, 1).Resize(, 4)
' -----> Set any chart properties here <-----
' Add Title
.SetElement msoElementChartTitleCenteredOverlay
.ChartTitle.Caption = cl.Value
'Change chart name
.Parent.Name = cl.Value
'Remove Legend
.SetElement (msoElementLegendNone)
' Adjust plot size to allow for title
.PlotArea.Height = .PlotArea.Height - .ChartTitle.Height
.PlotArea.Top = .PlotArea.Top + .ChartTitle.Height
'Change the x-axis to a more organized set
.SeriesCollection(1).XValues = "='Chart Data'!$F$2:$F$1048576"
'Set Max and Min for charts
.Axes(xlValue).MinimumScale = Sheets("Chart Data").Range("K1")
.Axes(xlValue).MaximumScale = Sheets("Chart Data").Range("K2")
'Adjust x-axis to tilt 45 degrees top left to bottom right
.Axes(xlCategory).TickLabels.Orientation = 45
End With
' Get next data set
rwStart = rwStart + rwCnt
Set cl = rAllData.Cells(rwStart, 1)
Loop
End With
under 'Change the x-axis to a more organized set, I used the following code:
.SeriesCollection(1).XValues = "='Chart Data'!" & rChartData.Offset(, 5).Resize(, 1).Address

Resources