Drawing a chart with owc chartspace in userform vba excel - excel

I have a little problem with my owc chartspace, I would like to draw a chart like in the picture but my problem is that it draws only for one series I would like to draw it for the 1 the 2 and the 3 I don't know how to do this.
I have a listbox and a combobox, I select from the list box the 1,2,3 and I select from the combobx y or z such that x is fixed.
Then I put the data in plage(1) for x and plage(2) for y but the problem is that it works only for the first item I select from the listbox ( in this picture the "1" )
Could you tell what is wrong in my code?
the vba code for drawing the chart into the userform is:
Private Sub drow()
Dim i, k As Integer, x As Integer
Dim j As Integer
Dim Table(), Plage(2)
Dim id As Integer
id = 1
Do While ComboBox.Value <> idi(id, 1)
id = id + 1
Loop
For i = Cht.SeriesCollection.Count To 1 Step -1
Cht.SeriesCollection.Delete i - 1
Next i
k = 1
ReDim Table(ListBox.ListCount)
For i = 0 To ListBox.ListCount - 1
If ListBox.Selected(i) = True Then
Table(k) = ListBox.List(i)
k = k + 1
End If
Next i
With Cht
.HasLegend = True
.Legend.Position = chLegendPositionBottom
.HasTitle = True
.Title.Caption = ComboBox.Text
End With
Cht.Type = C.chChartTypeColumnClustered3D
With Cht
'first serie
.SeriesCollection.Add
.SeriesCollection(0).Caption = sheet.Cells(2, 15 + id)
.SeriesCollection(0).DataLabelsCollection.Add
.SeriesCollection(0).DataLabelsCollection(0).Position = chLabelPositionCenter
.SeriesCollection(0).DataLabelsCollection(0).Font.Color = RGB(255, 255, 255)
.SeriesCollection.Add
.SeriesCollection(1).Caption = sheet.Cells(2, 20) .SeriesCollection(1).DataLabelsCollection.Add
.SeriesCollection(1).DataLabelsCollection(0).Position = chLabelPositionCenter
.SeriesCollection(1).DataLabelsCollection(0).Font.Color = RGB(255, 255, 255)
.SetData C1.chDimCategories, C1.chDataLiteral, Table
End With
For j = 0 To ListBox.ListCount - 1
If ListBox.Selected(j) = True Then
Plage(1) = sheet.Cells(j + 3, 15 + id) 'the Xs
Plage(2) = sheet.Cells(j + 3, 20) 'Les 'the Ys
With Cht
.SeriesCollection(0).SetData C1.chDimValues, C1.chDataLiteral, Plage(1)
.SeriesCollection(1).SetData C1.chDimValues, C1.chDataLiteral, Plage(2)
End With
Erase Plage
End If
Next j
End Sub

I am very new to the whole owc and VB thing and I am having some troubles myself, but have you tried using C1.chDimXValues and C1.chDimYValues instead of the chDimValues in the below statement:
.SeriesCollection(0).SetData
C1.chDimValues, C1.chDataLiteral,
Plage(1) .SeriesCollection(1).SetData
C1.chDimValues, C1.chDataLiteral,
Plage(2)
Sorry if this might sound trivial, I can see your coding skills are much more advanced than mine. Good luck!

Related

VBA scroll to text (search result)

I have a function which searchs through all the textboxes in a file and when it finds the text it automatically scrolls the window to the shape that contains the text.
Is it possible to:
a) scroll to the text, instead of the shape (scroll the page and center it on the search text result)
b) if not possible, then scroll to the middle of the shape (now it's going to the top)
If InStr(LCase(sTemp), LCase(sFind)) <> 0 Then
shp.Select
With shp.Line
.ForeColor.RGB = vbRed
.Weight = 5
End With
sFind2 = LCase(sFind)
sTemp2 = LCase(shp.TextFrame.Characters.Text)
iPos2 = InStr(sTemp2, sFind2)
If iPos2 > 0 Then
With shp.TextFrame.Characters(Start:=iPos2, _
Length:=Len(sFind2)).Font
.Size = 35
End With
End If
shp.Select
ActiveWindow.ScrollRow = shp.TopLeftCell.Row
ActiveWindow.ScrollColumn = shp.TopLeftCell.Column
End If
Useless to say: I am not an expert, sorry for the bad formatting.
a) you cannot scroll to a text. You can just scroll full rows and full columns.
b) you can do that only approximately, because you can just scroll full rows and full columns.
Since shp.TopLeftCell finds the top left cell under the shape, you can try to use the height/width of the shape and cells to find the cell that is approximately in the middle of the shape.
'scroll additional rows
Dim CellHeights As Double
CellHeights = shp.TopLeftCell.Height
Dim iRow As Long
Do While CellHeights < shp.Height / 2
CellHeights = CellHeights + shp.TopLeftCell.Offset(RowOffset:=iRow).Height
iRow = iRow + 1
Loop
ActiveWindow.ScrollRow = shp.TopLeftCell.Offset(RowOffset:=iRow).Row
'scroll additional columns
Dim CellWidths As Double
CellWidths = shp.TopLeftCell.Width
Dim iCol As Long
Do While CellWidths < shp.Width / 2
CellWidths = CellWidths + shp.TopLeftCell.Offset(ColumnOffset:=iCol).Width
iCol = iCol + 1
Loop
ActiveWindow.ScrollColumn = shp.TopLeftCell.Offset(ColumnOffset:=iCol).Column

Delete all ActiveX Checkboxes and then create new ones starting from 1

I've got a button that creates checkboxes. If I press it again I want to delete the previous checkboxes made and replace them with new ones. This is the code for the delete and create new part:
Dim s As Shape
For Each s In ActiveSheet.Shapes
If s.Type = 12 Then
If Not Intersect(s.TopLeftCell, Sheets("EmpChoice").Range("A14:T33")) Is Nothing Then
s.Delete
End If
End If
Next
Dim obj As Object
Dim rng As Range
For i = 1 To EmployeeNo
If i > 6 And i < 13 Then 'Just code that spaces the checkboxes out evenly
col = 3
offset = 12
ElseIf i >= 13 Then
col = 5
offset = 24
Else
col = 1
offset = 0
End If
Set rng = Sheets("EmpChoice").Cells(14 + (i * 2) - offset, col)
cellLeft = rng.Left
cellTop = rng.Top
cellwidth = rng.Width
cellheight = rng.Height
Set obj = ActiveSheet.OLEObjects.Add(ClassType:="Forms.Checkbox.1", Left:=cellLeft, Top:=cellTop, Width:=cellwidth * 2, Height:=cellheight * 2)
ActiveSheet.OLEObjects("CheckBox" & i).Object.Caption = EmployeeList(i)
Next i
The problem is that if the code creates 18 checkboxes and then deletes them, the new ones starts with the name "CheckBox19", crashing the code. Is it possible to make sure that the new checkboxes starts at "CheckBox1"?
Trying inserting of the obj name, like in the next piece of code:
Set obj = ActiveSheet.OLEObjects.Add(ClassType:="Forms.Checkbox.1", Left:=cellLeft, Top:=cellTop, Width:=cellwidth * 2, Height:=cellheight * 2)
obj.Name = "CheckBox" & i 'Here you can choose the name you need...
'Otherwise, VBA keeps track of the previous created objects
ActiveSheet.OLEObjects("CheckBox" & i).Object.Caption = EmployeeList(i)

Deselecting a chart in Excel VBA

In reference to the following file.xlsm:
where Sheet1 (1) is a Sheet, Plot1 (2) is a Graphic-Sheet and the button (3) refers to the following Macro:
Sub plot()
ReDim blue(1 To 5, 1 To 2)
ReDim red(1 To 5, 1 To 2)
For i = 1 To 5
blue(i, 1) = i
blue(i, 2) = i ^ 2
red(i, 1) = i + 4
red(i, 2) = (i + 4) ^ 2
Next i
Sheets("Plot1").Select
ActiveChart.ChartArea.ClearContents
ActiveChart.ChartArea.Select
ActiveChart.ChartType = xlXYScatterSmoothNoMarkers
ActiveChart.SeriesCollection.NewSeries
ActiveChart.FullSeriesCollection(1).XValues = Application.Index(blue, , 1)
ActiveChart.FullSeriesCollection(1).Values = Application.Index(blue, , 2)
ActiveChart.FullSeriesCollection(1).Select
Selection.Format.Line.ForeColor.RGB = RGB(0, 0, 255)
ActiveChart.SeriesCollection.NewSeries
ActiveChart.FullSeriesCollection(2).XValues = Application.Index(red, , 1)
ActiveChart.FullSeriesCollection(2).Values = Application.Index(red, , 2)
ActiveChart.FullSeriesCollection(2).Select
Selection.Format.Line.ForeColor.RGB = RGB(255, 0, 0)
Sheets("Plot1").Protect DrawingObjects:=True, Contents:=False
Sheets("Plot1").Unprotect
Sheets("Sheet1").Select
End Sub
after opening file.xlsm, clicking (3) and (2) I get:
after opening file.xlsm, clicking (2), (1), (3) and (2) I get:
How can I change the Macro so that I always get the third image regardless of the click sequence?
It used to be possible to deselect a chart, that is, an embedded chart, but I don't remember if it worked on a chart sheet.
For some reason, no matter what I try, the chart area becomes selected when this code is first run after opening the workbook. (I even tried activating the chart sheet, then the worksheet, with a Workbook_Open procedure: no luck.) But you can avoid having the second series selected if you don't select it in the first place. Not selecting things actually makes the code run faster, usually not enough that you would notice, but it also prevents the little flash of tabs being activated.
Sub plot()
ReDim blue(1 To 5, 1 To 2) As Double
ReDim red(1 To 5, 1 To 2) As Double
Dim i As Long
For i = 1 To 5
blue(i, 1) = i
blue(i, 2) = i ^ 2
red(i, 1) = i + 4
red(i, 2) = (i + 4) ^ 2
Next i
With Charts("Plot1")
.ChartArea.ClearContents
.ChartType = xlXYScatterSmoothNoMarkers
With .SeriesCollection.NewSeries
.XValues = Application.Index(blue, , 1)
.Values = Application.Index(blue, , 2)
.Format.Line.ForeColor.RGB = RGB(0, 0, 255)
End With
With .SeriesCollection.NewSeries
.XValues = Application.Index(red, , 1)
.Values = Application.Index(red, , 2)
.Format.Line.ForeColor.RGB = RGB(255, 0, 0)
End With
End With
End Sub

Positioning labels on a donut-chart

I have the following code which attempts to add a datalabel to a point in a combined donut/pie-chart:
For Each co In .ChartObjects
With co.Chart.FullSeriesCollection("Grøn pil").Points(2)
.HasDataLabel = True
With .DataLabel
.Position = xlLabelPositionOutsideEnd
.Format.AutoShapeType = msoShapeRectangle
.Format.Line.Visible = msoTrue
End With
End With
Next co
However, the code aborts on the line .Position = xlLabelPositionOutsideEnd with the error message "Run-time error 2147467259 (80004005)". Method 'Position' of object 'DataLabel' failed".
Looking at the chart, the label has been added, but it is still positioned inside the chart.
As you can see I've already positioned a label outside the chart for a different series, which is represented as a pie chart. While the series I am trying to add the label to is represented as a donut-chart.
Can't I have both the labels for the donut- and pie-chart on the outside? Isn't xlLabelPositionOutsideEnd a valid position for labels of a donut-chart? Or is the problem something else which eludes me?
Any help would be greatly appreciated!
I don't think it's possible to do exactly you want to do the way you want to do it! The option to place the labels outside the chart is not available on the doughnut chart options:
like they do on a pie chart:
However, you could perform a trick using a pie chart and a white circle to make it look like a doughnut by doing the following:
Sub AddCircle()
'Get chart size and position:
Dim CH01 As Chart: Set CH01 = ThisWorkbook.Sheets("Sheet1").ChartObjects("Chart1").Chart
Dim OB01 As ChartObject: Set OB01 = CH01.Parent
Dim x As Double: x = 0 'horizontal coordinate
Dim y As Double: y = 0 'vertical coordinate
Dim w As Double: w = 0 'width
Dim h As Double: h = 0 'height
x = OB01.Left
y = OB01.Top
w = OB01.Width
h = OB01.Height
'Adding the circle:
ThisWorkbook.Sheets("Sheet1").Shapes.AddShape(msoShapeOval, x + w / 2 - 20, y + h / 2 - 20, 40, 40).Name = "Circle01"
'Formatting the circle:
With ThisWorkbook.Sheets("Sheet1").Shapes("Circle01")
.LINE.Visible = msoFalse
.Fill.ForeColor.RGB = RGB(255, 255, 255)
End With
End Sub
And it works very nicely:
Had some fun "solving" this one...
Working with sinus and cosinus we can also calculate the outside position of the label. Following a VB snippet, how this can be done:
Sub Macro1()
Dim cx
Dim cy
Dim x
Dim y
Dim radius
Dim angle
Dim new_radius
Dim new_x
Dim new_y
ActiveSheet.ChartObjects("Chart 1").Activate
ActiveSheet.ChartObjects("Chart 1").Select
cx = Selection.width / 2
cy = Selection.height / 2
For i = 1 To ActiveChart.FullSeriesCollection(1).Points.Count Step 1
ActiveChart.FullSeriesCollection(1).Points(i).DataLabel.Select
x = Selection.left + (Selection.width / 2)
y = Selection.top + (Selection.height / 2)
radius = Sqr(((x - cx) ^ 2) + ((y - cy) ^ 2))
angle = WorksheetFunction.Atan2(y - cy, x - cx)
new_radius = radius + 40
new_x = cx + (Sin(angle) * new_radius)
new_y = cy + (Cos(angle) * new_radius)
Selection.left = new_x - (Selection.width / 2)
Selection.top = new_y - (Selection.height / 2)
Next i
End Sub

Set cell size equal to picture size

I'm trying to import a picture to excel cell and I'm facing issues with re-sizing.
Steps:
Copy/Paste the picture to the cell
Re-size the picture manually
And also resize the cell to fix on the picture.
Is there any other way to do it instead of manually?
I'm not sure what exactly you meant with re size the picture manually, but might this be working for you?
Sub ResizeCells()
Dim X As Double, Y As Double, Z As Double
Dim s As Shape
For Each s In ActiveSheet.Shapes
If s.Type = msoPicture Then
For X = s.TopLeftCell.Column To s.BottomRightCell.Column
Y = Y + ActiveSheet.Cells(1, X).ColumnWidth
Next X
For X = s.TopLeftCell.Row To s.BottomRightCell.Row
Z = Z + ActiveSheet.Cells(1, X).RowHeight
Next X
s.TopLeftCell.ColumnWidth = Y
s.TopLeftCell.RowHeight = Z
End If
Next s
End Sub
Note:
Max RowHeight is 409
Max ColumnWidth is 255
This goes the other way.
We will insert a Shape from the Internet.
We will move it to cell B1.
We will resize the Shape (both height and width) to fit in B1First place this link in cell A1:
http://www.dogbreedinfo.com/images26/PugPurebredDogFawnBlackMax8YearsOld1.jpg
Then run:
Sub MAIN()
Call InstallPicture
Call PlaceAndSizeShape
End Sub
Sub InstallPicture()
Dim v As String
v = Cells(1, 1).Value
With ActiveSheet.Pictures
.Insert (v)
End With
End Sub
Sub PlaceAndSizeShape()
Dim s As Shape, B1 As Range, w As Double, h As Double
Set s = ActiveSheet.Shapes(1)
s.Select
Selection.ShapeRange.LockAspectRatio = msoFalse
Set B1 = Range("B1")
s.Top = B1.Top
s.Left = B1.Left
s.Height = B1.Height
s.Width = B1.Width
End Sub
This post is old, but nobody mentioned resizing the picture to match the cell.
Excel is very unreliable when I tired to scale the width using #Andrew's code. Luckily, rCell.Left is in the correct units. You can get the actual column width using:
rCell.Offset(0, 1).Left - rCell.Left
This Code will Resize the Cell to Your Picture
Sub ResizePictureCells()
For Each Picture In ActiveSheet.DrawingObjects
PictureTop = Picture.Top
PictureLeft = Picture.Left
PictureHeight = Picture.Height
PictureWidth = Picture.Width
For N = 2 To 256
If Columns(N).Left > PictureLeft Then
PictureColumn = N - 1
Exit For
End If
Next N
For N = 2 To 65536
If Rows(N).Top > PictureTop Then
PictureRow = N - 1
Exit For
End If
Next N
Rows(PictureRow).RowHeight = PictureHeight
Columns(PictureColumn).ColumnWidth = PictureWidth * (54.29 / 288)
Picture.Top = Cells(PictureRow, PictureColumn).Top
Picture.Left = Cells(PictureRow, PictureColumn).Left
Next Picture
End Sub

Resources