So I've this chart that is made trought VBA
And now i want to put the data inside bars, so it will look like this:
Can you help?
The code that i've to get to this chart is:
Set rng = ActiveSheet.Range("A" & x & ":C" & (x + 4))
' in brackets (Left, Top, Widht, Height) >> modify according to your needs
Set cht = ActiveSheet.ChartObjects.Add(550, 100 * (i - 4), 300, 100)
With cht
.Chart.SetSourceData Source:=rng
.Chart.PlotBy = xlColumns
.Chart.ChartType = xlBarStacked
.Chart.HasAxis(xlValue) = False
.Chart.HasLegend = False
.Chart.HasTitle = True
.Chart.ChartTitle.Text = Application.Sheets(i).Name
.Chart.ChartTitle.Font.Size = 10
.Chart.Axes(xlValue).HasMajorGridlines = False
.Chart.Parent.Name = Application.Sheets(i).Name
End With
cht.Activate
ActiveChart.ChartGroups(1).GapWidth = 10
With ActiveChart.Axes(xlCategory).TickLabels.Font
.Bold = msoFalse
.Size = 8
End With
Set cht_Series = cht.Chart.SeriesCollection(1)
cht_Series.Format.Fill.ForeColor.RGB = RGB(255, 255, 255)
Set cht_Series = cht.Chart.SeriesCollection(2)
cht_Series.Format.Fill.ForeColor.RGB = RGB(134, 188, 37)
Thanks!
To get what you want, you would need to add this line at the end of your code:
ActiveChart.SeriesCollection(2).HasDataLabels = True
Since you have defined a seriescollection object, this would also work:
cht_Series.HasDataLabels = True
You need to set series.HasDataLabels = true and series.datalabels.Position = xlLabelPositionCenter (or very similar, can't check with Excel).
Related
Hi i am making a organisational hierarchy chart and i want to have a textbox below each nodes. What i did until now was to retrieve the data and plot out the hierarchy. But how do i add textbox under them? I have to add 2 textboxes below each nodes. Any help will be appreciated!
Code:
Option Explicit
Sub OrgChart()
Dim ogSALayout As SmartArtLayout
Dim QNodes As SmartArtNodes
Dim QNode As SmartArtNode
Dim ogShp As Shape
Dim shp As Shape
Dim t As Long
Dim i As Long
Dim r As Long
For Each shp In ActiveSheet.Shapes
If shp.Type = msoSmartArt Then: shp.Delete
Next shp
Set ogSALayout = Application.SmartArtLayouts( _
"urn:microsoft.com/office/officeart/2009/3/layout/HorizontalOrganizationChart" _
)
Set ogShp = ActiveSheet.Shapes.AddSmartArt(ogSALayout, 630, 36, 1000, 1000)
Set QNodes = ogShp.SmartArt.AllNodes
t = QNodes.Count
For i = 2 To t: ogShp.SmartArt.Nodes(1).Delete: Next i
Set QNode = QNodes(1)
If Range("D1").Value = "CONFIRM" Then
QNode.Shapes.Fill.ForeColor.RGB = RGB(255, 0, 0)
ElseIf Range("D1").Value = "PENDING" Then
QNode.Shapes.Fill.ForeColor.RGB = RGB(128, 128, 128)
ElseIf Range("D1").Value = "SUSPECTED" Then
QNode.Shapes.Fill.ForeColor.RGB = RGB(255, 255, 0)
ElseIf Range("D1").Value = "NO" Then
QNode.Shapes.Fill.ForeColor.RGB = RGB(0, 255, 0)
End If
With QNode.TextFrame2.TextRange
.Text = Range("B1").Value
.Font.Fill.ForeColor.RGB = vbBlack
.Font.Size = 12
.Font.Bold = True
End With
With QNode.Shapes.AddTextbox(msoTextOrientationHorizontal, _
100, 100, 200, 50) _
.TextFrame.Characters.Text = "Test Box"
End With
r = 1
Call AddChildren(QNode, r)
ogShp.Copy
Sheets.Add After:=ActiveSheet
ActiveSheet.Paste
End Sub
Sub AddChildren(ByVal QParent As SmartArtNode, ByVal r As Long)
Dim QChild As SmartArtNode
Dim Level As Long
Dim s As Long
Const MyCol As String = "C"
Level = Range(MyCol & r).Value
s = r + 1
Do While Range(MyCol & s).Value > Level
If Range(MyCol & s).Value = Level + 1 Then
Set QChild = QParent.AddNode(msoSmartArtNodeBelow)
If Range("D" & s).Value = "CONFIRM" Then
QChild.Shapes.Fill.ForeColor.RGB = RGB(255, 0, 0)
ElseIf Range("D" & s).Value = "PENDING" Then
QChild.Shapes.Fill.ForeColor.RGB = RGB(128, 128, 128)
ElseIf Range("D" & s).Value = "SUSPECTED" Then
QChild.Shapes.Fill.ForeColor.RGB = RGB(255, 255, 0)
ElseIf Range("D" & s).Value = "NO" Then
QChild.Shapes.Fill.ForeColor.RGB = RGB(0, 255, 0)
End If
With QChild.TextFrame2.TextRange
.Text = Range("B" & s).Value
.Font.Fill.ForeColor.RGB = vbBlack
.Font.Size = 12
End With
Call AddChildren(QChild, s)
End If
s = s + 1
Loop
End Sub
This is what it looks like now:
Edit: Added screenshot of data layout.
Adding a textbox under a node would mean that you would have to move the node up to make room for the textbox. As far as I know, it's not possible to move the nodes using VBA.
As a workaround, you could create another node under each node and format it as a textbox.
The outcome would look something like this:
To do this, I would first remove this from OrgChart
With QNode.Shapes.AddTextbox(msoTextOrientationHorizontal, _
100, 100, 200, 50) _
.TextFrame.Characters.Text = "Test Box"
End With
And replace it with:
Dim PseudoTxtBox As SmartArtNode
Set PseudoTxtBox = QNode.AddNode(msoSmartArtNodeAfter) 'Pseudo text box
'Add some text to the textbox
With PseudoTxtBox.TextFrame2.TextRange
.Text = "Some Text"
.Font.Fill.ForeColor.RGB = vbBlack
.Font.Size = 12
End With
'Make the textbox background transparent
PseudoTxtBox.Shapes.Fill.Transparency = 1
Then I would insert the following code right after adding the node in AddChildren :
Dim PseudoTxtBox As SmartArtNode
Set PseudoTxtBox = QChild.AddNode(msoSmartArtNodeAfter) 'Pseudo text box
'Add some text to the textbox
With PseudoTxtBox.TextFrame2.TextRange
.Text = "Some Text"
.Font.Fill.ForeColor.RGB = vbBlack
.Font.Size = 12
End With
'Make the textbox background transparent
PseudoTxtBox.Shapes.Fill.Transparency = 1
'Get the parent shape
Dim mshp As Shape
Dim tempObject As Object
Set tempObject = QChild.Parent
Do While TypeName(tempObject) <> "Shape"
Set tempObject = tempObject.Parent
Loop
Set mshp = tempObject
'Set the corresponding connector (line) to be transparent.
mshp.GroupItems(Level).Line.Transparency = 1
How do I get the correct width of each legend entry in a chart? I have used the width property of the LegendEntry but this doesn't give the correct value.
For example, using the below legend:
if I check each legend entry's width using LegendEntry.Width I get the same width for each entry
A = 67, word = 67, Longer sentence = 67,
Which is obviously incorrect, it's probably assigned the longest width to all entries. So how do i get the actual width of each entry?
I know that the chart's legend entry is automatically resized according to the number of letters.
So it is an anomaly, but it seems to be necessary to adjust the number of characters to be blank. It is not an exact match, but space * 2 seems similar.
Sub setCharts(Target As Range, Cht As Chart)
Dim Srs As Series
Dim vColor, vName
Dim i As Integer, Ln As Integer, k As Integer
vColor = Array(RGB(246, 246, 246), RGB(255, 224, 140), RGB(47, 157, 39), RGB(0, 0, 0))
vName = Array("A", "Word", "Longer sentence", "stack")
Ln = Len(vName(2)) '<~~~ "Longer sentence" 's length --> Collection name
'****** The Loop statement below makes the series names the same length ******
' For i = 0 To UBound(vName)
' k = Ln - Len(vName(i))
' vName(i) = vName(i) & Space(k * 2)
' M = Len(vName(i))
' Next i
With Cht
.ChartType = xlColumnStacked
.HasLegend = True
.Legend.Position = xlLegendPositionBottom
.HasTitle = True
.ChartTitle.Text = Target.Value
.Axes(xlValue, xlPrimary).HasTitle = True
.Axes(xlValue, xlPrimary).AxisTitle.Characters.Text = "OCF Percentiles"
.Axes(xlValue).MajorUnit = 50
For Each Srs In .SeriesCollection
Srs.Delete
Next Srs
For i = 0 To 2
Set Srs = .SeriesCollection.NewSeries
With Srs
.Name = vName(i) '<~~ Collection name
.Values = Target.Offset(0, 1).Resize(3).Offset(0, i)
.XValues = Array("A", "D", "I")
.Format.Fill.ForeColor.RGB = vColor(i)
If i = 0 Then
.Format.Fill.Transparency = 0.5 '<~~~~~ Transparency was adjusted
End If
End With
Next i
Set Srs = .SeriesCollection.NewSeries
With Srs
.Name = vName(3) '<~~ Collection name
.ChartType = xlXYScatter
.Values = Target.Offset(0, 4).Resize(1, 3)
.MarkerStyle = xlMarkerStyleSquare
.MarkerBackgroundColor = vColor(3) 'vbBlack
End With
End With
End Sub
Before
After
Wrote a macro to draw line with markers plot with excel, it works well in a single macro xlsm file. But when I tried to convert it to a excel addin (xlam file) , it got a lot of bugs. All the bugs are related to the format of both X and Y coordinates, position, font type and size of chart title, and position, font type and sizeof added text. Not sure what is the reason, need to know the correct format of them. Any debug suggestions or help, really appreciated. Please see the error message and my full macro codes as the following. Thanks.
The error message is run time error '-21474627161 (800004003)': the object is no longer valid.
After you clicked the debug, the code " .left=358" was highlighted with yellow.
But you checked with excel, the plot was drawn without chart title and the add text (that I want) and the format of coordinate was not that I tried to set. Again all these errors only happen with the xlam file, the macro works well with xlms fie.
Sub strain_plot()
sh_rows = ActiveWorkbook.ActiveSheet.Range("B65535").End(xlUp).Row
For i = 1 To sh_rows
If ActiveSheet.Cells(i, 1).Value < 0.000001 Then
ActiveSheet.Cells(i, 1).Value = 1000000000# * ActiveSheet.Cells(i, 1).Value
End If
Next i
ii = sh_rows
c_name = "chart1"
On Error GoTo err:
ActiveWorkbook.ActiveSheet.ChartObjects(c_name).Delete
err:
Set ch = ActiveWorkbook.ActiveSheet.ChartObjects.Add(330, 120, 480, 270) 'set graph position and size
ch.Name = c_name
With ch.Chart
For iii = 1 To 2
.SeriesCollection.NewSeries
.SeriesCollection(iii).Values = Range(ActiveWorkbook.ActiveSheet.Cells(1, iii + 1), ActiveWorkbook.ActiveSheet.Cells(ii, iii + 1))
.SeriesCollection(iii).XValues = Range(ActiveWorkbook.ActiveSheet.Cells(1, 1), ActiveWorkbook.ActiveSheet.Cells(ii, 1))
.SeriesCollection(iii).ChartType = xlLineMarkers
Next iii
.SeriesCollection(1).Name = "[110]"
.SeriesCollection(1).MarkerStyle = 2
.SeriesCollection(1).MarkerSize = 12
.SeriesCollection(1).MarkerForegroundColor = RGB(255, 0, 0)
.SeriesCollection(1).MarkerBackgroundColor = RGB(255, 0, 0)
.SeriesCollection(1).Format.Fill.ForeColor.RGB = RGB(255, 0, 0)
.SeriesCollection(2).Name = "[001]"
.SeriesCollection(2).MarkerStyle = 2
.SeriesCollection(2).MarkerSize = 12
.SeriesCollection(2).MarkerForegroundColor = RGB(96, 96, 96)
.SeriesCollection(2).MarkerBackgroundColor = RGB(96, 96, 96)
.SeriesCollection(2).Format.Fill.ForeColor.RGB = RGB(96, 96, 96)
With .Legend
.IncludeInLayout = False
.Position = xlLegendPositionRight
.AutoScaleFont = False
.Font.Size = 14
.Top = 25
.Left = 392
.Width = 72
.Height = 40
End With
With .ChartArea.Fill
.Visible = msoTrue
.ForeColor.SchemeColor = 33
.Solid
End With
With .SeriesCollection(1).Format.Line
.Visible = msoTrue
.ForeColor.RGB = RGB(255, 0, 0) 'red
.Transparency = 0
End With
With .SeriesCollection(2).Format.Line
.Visible = msoTrue
.ForeColor.RGB = RGB(96, 96, 96) 'grey
.Transparency = 0
End With
.HasTitle = True
With .ChartTitle
.Text = ActiveWorkbook.ActiveSheet.Cells(5, 8)
.Left = 358
.Top = 236
With .Font
.Name = "Tahoma"
.Size = 10
End With
End With
With .Axes(xlCategory)
.HasTitle = True
.AxisTitle.Text = "Position(nm)" 'X-axis title
.TickLabels.Font.Size = 10 'X-axis coordinate number size
.AxisTitle.Font.Size = 14 'X-axis title word font size
.TickMarkSpacing = 3
.TickLabelSpacing = 5
.TickLabels.NumberFormatLocal = "#,##0._);[red](#,##0.)"
.TickLabels.NumberFormatLocal = "#,##0_);[red](#,##0)"
.TickLabels.NumberFormatLocal = "0_);[red](0.)"
End With
With .Axes(xlValue)
.HasTitle = True
.AxisTitle.Text = "Strain" 'Y-aixs title
.AxisTitle.Font.Size = 14 'y-axis title word font size
'Minimum value of Y axis
.Axes(xlValue).MinimumScale = -0.005
.Axes(xlValue).TickLabels.NumberFormatLocal = "0.0%"
End With
End With
Dim thechartobj As ChartObject
Set thechartobj = ActiveWorkbook.ActiveSheet.ChartObjects(ch.Name)
Dim thechart As Chart
Set thechart = thechartobj.Chart
Dim thetextbox As Shape
Set thetextbox = thechart.Shapes.AddTextbox(msoTextOrientationHorizontal, 688, 372, 122, 20)
With thetextbox.TextFrame.Characters
.Text = ActiveSheet.Cells(6, 8)
With .Font
.Name = "tahoma"
.Size = 10
.Bold = msoTrue
End With
End With
End Sub
I have a VBA script that I use to generate multiple line charts in Excel. It used to include 2 series collections per chart (reading from 2 columns) but I since modified it for only one. However now I want it to do 2 series' again but want it to read both collections from the same column. Is this possible?
I've tried modifying the .SeriesCollection(2) to go to the next range further down the column. However this just returns an error 4001.
Sub CreateCharts()
Dim ws As Worksheet
Dim ch As Chart
Dim NumCharts As Integer, ChartName As String, ChartTitle As String, i As Integer
Set ws = Sheets("Charts")
NumCharts = WorksheetFunction.CountA(ws.Rows(2))
For i = 2 To NumCharts Step 1 '1 column of data per chart
ChartName = ws.Cells(2, i) '"chrt" & Range(Col1 & 2)
ChartTitle = ws.Cells(2, i) 'Range(Col1 & 2)
Set ch = Charts.Add
With ch
.ChartType = xlLine
.SetSourceData Source:=ws.Range(ws.Cells(3, i), ws.Cells(20, i)), _
PlotBy:=xlColumns 'range of data for each chart
.SeriesCollection(1).XValues = ws.Range("A3:A20") 'data range of line 1 (test data)
.SeriesCollection(2).XValues = ws.Range("A21:A38") 'data range of line 2 (Rw curve)
.Name = ChartName
.HasTitle = True
.ChartTitle.Characters.text = "#" & ws.Cells(2, i) '& " " & ws.Cells(1, i) 'remove title 'change to "ws.Cells(2, i)" to see titles
.ChartTitle.Left = 600
'HORiZONTAL X AXiS
.Axes(xlCategory, xlPrimary).HasTitle = True
.Axes(xlCategory, xlPrimary).AxisTitle.Characters.text = "Frequency (Hz)"
.Axes(xlCategory).MajorTickMark = xlNone
.Axes(xlCategory).AxisBetweenCategories = False
.Axes(xlCategory).Border.LineStyle = None
'VERTiCAL Y AXiS
.Axes(xlValue, xlPrimary).HasTitle = True
.Axes(xlValue, xlPrimary).AxisTitle.Characters.text = "Sound Reduction Index (dB)"
.Axes(xlValue).TickLabels.NumberFormat = "0"
.Axes(xlValue).MajorTickMark = xlNone
.Axes(xlValue).HasMajorGridlines = False
.Axes(xlValue).MinimumScale = 10 'minimum value on y
.Axes(xlValue).MaximumScale = 80 'maximum value on y
.Axes(xlValue).Border.LineStyle = None
'LEGEND
.HasLegend = False
'FONT SPECiFiCATiONS
.ChartArea.Format.TextFrame2.TextRange.Font.Size = 14
.ChartArea.Format.TextFrame2.TextRange.Font.Name = "Myriad Pro"
.ChartArea.Border.LineStyle = xlNone
'CHART POSiTiON, SiZE & COLOUR
.PlotArea.Format.Fill.ForeColor.RGB = RGB(242, 242, 242) 'grey background
.PlotArea.Top = 0
.PlotArea.Left = 20
.PlotArea.Height = 440
.PlotArea.Width = 420
'CHART LiNE COLOURS
.SeriesCollection(1).Border.Color = RGB(27, 117, 188) 'first line colour
'.SeriesCollection(2).Border.Color = RGB(0, 0, 0) 'second line colour
'.SeriesCollection(2).LineStyle = xlDashDot
End With
Next i
End Sub
Here is an image example of what I'm wanting to achieve.
Code is slightly modified and tested to work as far my understanding of the objective (to create one 2 series charts per column. 1st series Row 3-20 and 2nd series 21 to 38). Only issue with code was absence of SeriesCollection(2). It is modified to add necessary SeriesCollection and to delete if any automatically added series collection exist.
For i = 2 To NumCharts Step 1 '1 column of data per chart
ChartName = ws.Cells(2, i) '"chrt" & Range(Col1 & 2)
ChartTitle = ws.Cells(2, i) 'Range(Col1 & 2)
Set ch = Charts.Add
'Delete if any automatically added series exist
For x = ch.SeriesCollection.Count To 1 Step -1
ch.SeriesCollection(x).Delete
Next
With ch
.ChartType = xlLine
.SeriesCollection.Add ws.Range(ws.Cells(3, i), ws.Cells(20, i))
.SeriesCollection.Add ws.Range(ws.Cells(21, i), ws.Cells(38, i))
.SeriesCollection(1).XValues = ws.Range(ws.Cells(3, 1), ws.Cells(20, 1))
.SeriesCollection(2).XValues = ws.Range(ws.Cells(21, 1), ws.Cells(38, 1))
.Name = ChartName
I have a macro which adds and removes (filterseries) set data series of a chart (in its own sheet) by looping through checkboxes in a separate sheet. When I add and remove them, I want to cycle the legend off then back on so that it resizes itself automatically.
I think this is just a syntax error of how I'm using the with statement.
I have a separate macro which does this for a different purpose, but it loops through chart-sheets and treats them as variables and, for some reason, it works there.
Sub ISurfSeries1Checklist()
Application.ScreenUpdating = False
Application.EnableEvents = False
Dim i As Integer
Dim c As Integer
For i = 1 To 56
If ActiveWorkbook.Sheets("Range").Cells(3 + i, 12).Value = True Then
ActiveWorkbook.Charts("I. Surf (1)").FullSeriesCollection(i).IsFiltered = False
Else 'ActiveWorkbook.Sheets("Range").Cells(3 + i, 12) = False Then
ActiveWorkbook.Charts("I. Surf (1)").FullSeriesCollection(i).IsFiltered = True
End If
Next i
For c = 51 To 56 'ActiveWorkbook.Charts("I. Surf (1)").FullSeriesCollection.Count
ActiveWorkbook.Charts("I. Surf (1)").FullSeriesCollection(c).Format.Line.Visible = msoTrue
ActiveWorkbook.Charts("I. Surf (1)").FullSeriesCollection(c).Format.Line.ForeColor.RGB = RGB(255, 0, 0)
ActiveWorkbook.Charts("I. Surf (1)").FullSeriesCollection(c).Format.Line.Transparency = 0
Next c
ActiveWorkbook.Charts("I. Surf (1)").HasLegend = False
ActiveWorkbook.Charts("I. Surf (1)").HasLegend = True
'***Below is where it stops working.***
With ActiveWorkbook.Charts("I.Surf (1)").Legend
.Font.Size = 8
.Border.Weight = xlHairline
.Border.Color = RGB(89, 89, 89)
.Interior.Color = RGB(255, 255, 255)
.Left = Cht_Sht.PlotArea.InsideLeft - Cht_Sht.Axes(xlValue).Format.Line.Weight
.Top = Cht_Sht.PlotArea.InsideTop
End With
Runtime Error '9'. Subscript out of range
on the With statement: With ActiveWorkbook.Charts("I.Surf (1)").Legend
That means a chart named "I.Surf (1)" does not exist you are probably missing the space between the dot and Surf. It should be "I. Surf (1)".
I recommend to reference the chart by a variable so you only have to use its name once. Coding rule number 1: Don't repeat yourself.
Dim ActChart As Chart
Set ActChart = ActiveWorkbook.Charts("I. Surf (1)")
This prevents typos and if you have to change it you only need to change it in one position:
Sub ISurfSeries1Checklist()
Application.ScreenUpdating = False
Application.EnableEvents = False
Dim ActChart As Chart
Set ActChart = ActiveWorkbook.Charts("I. Surf (1)")
Dim i As Long
For i = 1 To 56
'Note that you can shorten this to:
ActChart.FullSeriesCollection(i).IsFiltered = Not (ActiveWorkbook.Sheets("Range").Cells(3 + i, 12).Value = True)
Next i
Dim c As Long
For c = 51 To 56 'ActiveWorkbook.Charts("I. Surf (1)").FullSeriesCollection.Count
With ActChart.FullSeriesCollection(c).Format.Line
.Visible = msoTrue
.ForeColor.RGB = RGB(255, 0, 0)
.Transparency = 0
End With
Next c
ActChart.HasLegend = False
ActChart.HasLegend = True
With ActChart.Legend
.Font.Size = 8
.Border.Weight = xlHairline
.Border.Color = RGB(89, 89, 89)
.Interior.Color = RGB(255, 255, 255)
.Left = Cht_Sht.PlotArea.InsideLeft - Cht_Sht.Axes(xlValue).Format.Line.Weight
.Top = Cht_Sht.PlotArea.InsideTop
End With
End Sub