Save image of range in next column excel vba - vba

On the activesheet in column A, I have text of which I want to save image and place it in column B.
I can't figure out how to remove the lines and axis etc and just get a image of the range. Currently it's showing lines and axis in the image.
Sub Generate_Images()
Dim wK As Worksheet
Dim oCht As Chart
Dim i As Long, fI As Long
Dim fName As String
Application.DisplayAlerts = False
Set wK = ActiveSheet
fI = wK.Range("A" & wK.Rows.Count).End(xlUp).Row
wK.Columns("B:B").ColumnWidth = wK.Columns("A:A").ColumnWidth
For i = 1 To fI
wK.Range("A" & i).CopyPicture xlScreen, xlBitmap
Set oCht = ThisWorkbook.Charts.Add
With oCht
.ChartArea.Border.LineStyle = xlNone
.Paste
fName = ThisWorkbook.Path & "\" & Format(Now(), "DDMMYYHHMMSS") & ".png"
.Export Filename:=fName, Filtername:="PNG"
.Delete
End With
With wK.Pictures.Insert(fName)
With .ShapeRange
.LockAspectRatio = msoTrue
.Width = wK.Range("A" & i).Width
.Height = wK.Range("A" & i).Height
End With
.Left = wK.Range("B" & i).Left
.Top = wK.Range("B" & i).Top
.Placement = 1
.PrintObject = True
End With
Application.Wait Now + TimeValue("00:00:01")
Next i
Application.DisplayAlerts = True
End Sub

Why export and then re-import the image when you can just paste it straight into the sheet?
Sub Generate_Images()
Dim wK As Worksheet
Dim oCht As Chart
Dim i As Long, fI As Long
Dim fName As String
Application.DisplayAlerts = False
Set wK = ActiveSheet
fI = wK.Range("A" & wK.Rows.Count).End(xlUp).Row
wK.Columns("B:B").ColumnWidth = wK.Columns("A:A").ColumnWidth
For i = 1 To fI
wK.Range("A" & i).CopyPicture xlScreen, xlBitmap
wK.Paste
With wK.Pictures(wK.Pictures.Count)
.Left = wK.Range("B" & i).Left
.Top = wK.Range("B" & i).Top
.Placement = 1
.PrintObject = True
End With
Application.Wait Now + TimeValue("00:00:01")
Next i
Application.DisplayAlerts = True
End Sub

If you save image to picture file, then try this.
Instead Chart, use chartobject. It is possible to change chart's size.
And if your active cell is not empty, Excell automatically create chart base on data.
So, you must delete chart's seriescollecton.
Sub Generate_Images()
Dim wK As Worksheet
Dim oCht As Chart
Dim i As Long, fI As Long, j As Long
Dim fName As String
Dim obj As ChartObject
Dim n As Long
Dim w As Single, h As Single
Application.DisplayAlerts = False
Set wK = ActiveSheet
wK.Pictures.Delete
fI = wK.Range("A" & wK.Rows.Count).End(xlUp).Row
wK.Columns("B:B").ColumnWidth = wK.Columns("A:A").ColumnWidth
For i = 1 To fI
w = wK.Range("A" & i).Width
h = wK.Range("A" & i).Height
wK.Range("A" & i).CopyPicture xlScreen, xlBitmap
Set obj = wK.ChartObjects.Add(Range("c1").Left, 0, w, h)
Set oCht = obj.Chart
With oCht
n = .SeriesCollection.Count
For j = n To 1 Step -1
.SeriesCollection(j).Delete
Next j
.ChartArea.Border.LineStyle = xlNone
.Paste
fName = ThisWorkbook.Path & "\" & Format(Now(), "DDMMYYHHMMSS") & ".png"
.Export Filename:=fName, Filtername:="PNG"
obj.Delete
End With
With wK.Pictures.Insert(fName)
.Left = wK.Range("B" & i).Left
.Top = wK.Range("B" & i).Top
.Placement = 1
.PrintObject = True
End With
Application.Wait Now + TimeValue("00:00:01")
Next i
Application.DisplayAlerts = True
End Sub

Related

Exclude certain columns form range

Having trouble coding a macro in vba to exclude certain columns from being included in a chart. I want to exclude Column F from being included. Here is my code from a recoreded macro that I tweaked a bit:
Sub Macro4()
Dim ws As Worksheet
Dim wb As Workbook
Set wb = ThisWorkbook
Set ws = wb.Sheets("Sheet1")
ActiveSheet.Shapes.AddChart2(251, xlBarClustered).Select
ActiveChart.SetSourceData Source:=ws.Range("E" & ActiveCell.Row & ":F" & ActiveCell.Row & ":G" & ActiveCell.Row & ":H" & ActiveCell.Row)
ActiveChart.FullSeriesCollection(1).XValues = "=Sheet1!$E$9:$H$9"
ActiveChart.SetElement (msoElementDataLabelOutSideEnd)
ActiveChart.SetElement (msoElementPrimaryCategoryGridLinesNone)
ActiveChart.Axes(xlValue).MajorGridlines.Format.Line.Visible = msoFalse
ActiveChart.FullSeriesCollection(1).DataLabels.ShowCategoryName = False
With ActiveChart
.HasTitle = True
.ChartTitle.Characters.Text = "Analysis for " & ws.Range("C" & ActiveCell.Row)
ActiveChart.HasAxis(xlValue) = False
ActiveChart.HasLegend = False
End With
End Sub
Try the following, you use "," to delimit non-consecutive ranges:
ActiveChart.SetSourceData Source:=ws.Range("Sheet1!$E$" & ActiveCell.Row & ",Sheet1!$G$" & ActiveCell.Row & ",Sheet1!$H$" & ActiveCell.Row)
ActiveChart.FullSeriesCollection(1).XValues = "=Sheet1!$E$9,Sheet1!$G$9,Sheet1!$H$9"
This should exclude F from your chart.
Edit:
To create your chart only using data from the active row, you can try:
Sub Macro4()
Dim wb As Workbook: Set wb = ThisWorkbook
Dim ws As Worksheet: Set ws = wb.Sheets("Sheet1")
ws.Activate
Dim MyRange1 As Range: Set MyRange1 = Range("E" & ActiveCell.Row)
Dim MyRange2 As Range: Set MyRange2 = Range(Cells(ActiveCell.Row, "G"), Cells(ActiveCell.Row, "H"))
Dim MyChartRange As Range: Set MyChartRange = Union(MyRange1, MyRange2)
ActiveSheet.Shapes.AddChart2(251, xlBarClustered).Select
ActiveChart.SetSourceData Source:=MyChartRange
ActiveChart.FullSeriesCollection(1).XValues = "=Sheet1!$E$9:$H$9"
ActiveChart.SetElement (msoElementDataLabelOutSideEnd)
ActiveChart.SetElement (msoElementPrimaryCategoryGridLinesNone)
ActiveChart.Axes(xlValue).MajorGridlines.Format.Line.Visible = msoFalse
ActiveChart.FullSeriesCollection(1).DataLabels.ShowCategoryName = False
With ActiveChart
.HasTitle = True
.ChartTitle.Characters.Text = "Analysis for " & ws.Range("C" & ActiveCell.Row)
ActiveChart.HasAxis(xlValue) = False
ActiveChart.HasLegend = False
End With
End Sub

How to save worksheets in a csv format while keeping the column separation format?

I'm working on a VBA code that creates multiple sheets from a source (Sheets). I'm trying to save them separately in a CSV format to use them for batch input. However, the requirement is that the saved worksheets must stay in "a column separation format" while in a CSV file.
Here is where I'm at:
For i = 0 To nb
If Sheets("PjtDef").Range("A2").Offset(k + i, 0).Value <> "" Then
Sheets("PjtDef").Range("A2").Offset(k + i, 0).Select
Sheets("PjtDef").Range("A1", ActiveCell).EntireRow.Copy
Sheets.Add
ActiveSheet.Name = h
ActiveSheet.Paste
Worksheets("PjtDef").Activate
Sheets("PjtDef").Range("A2").Offset(k + i, 0).Select
Range("A2", ActiveCell).EntireRow.Delete Shift:=xlUp
h = h + 1
Else: i = nb
End If
Next i
Dim xWs As Worksheet
Dim xcsvFile As String
For Each Scut In Application.ActiveWorkbook.Worksheets
Scut.Copy
Name = CurDir & "\" & Scut.Name & ".csv"
Application.ActiveWorkbook.SaveAs Filename:=Name, _
FileFormat:=xlCSV, CreateBackup:=False
Application.ActiveWorkbook.Saved = True
Application.ActiveWorkbook.Close
Next
Application.ScreenUpdating = True
End Sub
I have next code working:
Sub ExportFile()
Const myDelim As String = "|"
Dim Sheet As Object
Set Sheet = Worksheets
For p = 1 To 2 'you could use sheet.count
Sheet(p).Activate
Dim ws As Worksheet
Set ws = ActiveSheet
Dim r As Long, c As Long, i As Long, j As Long
r = ws.Cells.Find(What:="*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
c = ws.Cells.Find(What:="*", SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column
Dim myPath As String
myPath = ThisWorkbook.Path & "\"
Dim myFile As String
filename = ws.name
myFile = myPath & filename & ".extention"
Dim obj As Object
Set obj = CreateObject("ADODB.Stream")
obj.Type = 2
obj.Charset = "ASCII"
obj.Open
Dim v() As Variant
ReDim v(1 To c)
For i = 3 To r - 1
For j = 1 To c
v(j) = ws.Cells(i, j).Text
Next
obj.WriteText Join(v, myDelim), 1
Next
obj.SaveToFile myFile, 2
End Sub
This writes all sheet to a file separating cells in rows by "|"

excel vba table query connection properties

I am trying to display the properties of all tables in a workbook. The code I am using is working but I am missing some information. As a matter of fact, some of the queries attached do not match the real query being used by the table
Below is the entire code used (the module wb parameter is a parameter from a user form list box)
Public Sub WbkConnProperties(wb As Workbook)
Dim WS As Worksheet
Dim objWBConnect As WorkbookConnection
Dim vWs() As String
Dim lOffset As Long
Dim lastr As Long, lastc As Long
Dim wsnm As String
Dim i As Long
Dim iex As Byte
'On Error Resume Next
'make sure we have at least one visible sheet
Application.DisplayAlerts = False
With ThisWorkbook
'For Each ws In .Worksheets
' If Not ws.Name = .Worksheets(1).Name Then
' ws.Delete
' End If
'Next ws
ReDim vWs(ThisWorkbook.Worksheets.Count)
i = 0
For Each WS In .Worksheets
vWs(i) = WS.Name
i = i + 1
Next WS
wsnm = Left(wb.Name, 20) & Right(wb.Name, 5)
iex = 0
For i = LBound(vWs, 1) To UBound(vWs, 1)
If vWs(i) = wsnm & "_" & iex Or vWs(i) = wsnm Then
iex = iex + 1
End If
Next i
If iex > 0 Then
.Worksheets.Add After:=Worksheets(Worksheets.Count)
.Worksheets(.Worksheets.Count).Name = wsnm & "_" & iex
Set WS = .Worksheets(wsnm & "_" & iex)
Else
.Worksheets.Add After:=Worksheets(Worksheets.Count)
.Worksheets(.Worksheets.Count).Name = wsnm
Set WS = .Worksheets(wsnm)
End If
End With 'thisw
Application.DisplayAlerts = True
'ActiveWindow.FreezePanes = False
With WS.Range("A1:G1")
.Value = Array("Worksheet name", "Connection Name", _
"Data file source", "Sql Query text", "Data file path", _
"Connection String", "Connection Type")
End With
'________________________________________________________________________
'___
'___ col.1 - 0 - Nom de la feuille où se trouve le résultat de la requête
'___ col.2 - 1 - Nom de la connection relative à la feuille col.1
'___ col.3 - 2 - Nom du classeur des données sources (si applicable)
'___ col.4 - 3 - Requête sql
'___ col.5 - 4 - Chemin du classeur des données sources
'___ col.6 - 5 - Propriétés de la connection
'___ col.7 - 6 - Type de la connection (pour info. ce code peut
'___ s'appliquer pour les TCD)
'________________________________________________________________________
'ws.Cells.EntireColumn.AutoFit
With WS
With .Range("A1")
lOffset = 0
For Each objWBConnect In wb.Connections
lOffset = lOffset + 1
.Offset(lOffset, 0).Value = "nom_feuille"
.Offset(lOffset, 1).Value = objWBConnect.Name
.Offset(lOffset, 2).Value = "classeur_donnees_src"
.Offset(lOffset, 6).Value = objWBConnect.Type
If objWBConnect.Type = xlConnectionTypeODBC Then
.Offset(lOffset, 3).Value = objWBConnect.ODBCConnection.CommandText
.Offset(lOffset, 5).Value = objWBConnect.ODBCConnection.Connection
.Offset(lOffset, 2).Value = FWorkbookName(.Offset(lOffset, 5).Value)
.Offset(lOffset, 4).Value = FWorkbookPath(.Offset(lOffset, 5).Value)
.Offset(lOffset, 0).Value = GetRange(wb, .Offset(lOffset, 1).Value)
ElseIf objWBConnect.Type = xlConnectionTypeOLEDB Then
.Offset(lOffset, 5).Value = objWBConnect.OLEDBConnection.Connection
Else
.Offset(lOffset, 5).Value = "Not Applicable"
End If
Next objWBConnect
End With
lastr = .Cells(.Rows.Count, 1).End(xlUp).Row
lastc = .Cells(1, Columns.Count).End(xlToLeft).Column
With .Cells
.HorizontalAlignment = xlGeneral
.VerticalAlignment = xlCenter
End With
.Columns("A:A").EntireColumn.AutoFit
.Columns("B:B").ColumnWidth = 40
.Columns("C:C").ColumnWidth = 40
With .Columns("D:D")
.ColumnWidth = 75
.Replace What:="`", Replacement:="", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
End With
.Columns("E:E").ColumnWidth = 50
.Columns("E:E").WrapText = True
.Columns("F:F").ColumnWidth = 80
.Columns("F:F").WrapText = True
With .Columns("G:G")
.HorizontalAlignment = xlCenter
.VerticalAlignment = xlCenter
.EntireColumn.AutoFit
End With
With .Range(.Cells(1, 1), .Cells(1, lastc))
.VerticalAlignment = xlCenter
.HorizontalAlignment = xlCenter
.RowHeight = 25
.Font.Bold = True
End With
With .Range(.Cells(2, 1), .Cells(lastr, lastc))
.VerticalAlignment = xlCenter
.WrapText = True
End With
With .Columns("G:G")
.HorizontalAlignment = xlCenter
.VerticalAlignment = xlCenter
.Orientation = 0
.AddIndent = False
.IndentLevel = 0
.ShrinkToFit = False
.ReadingOrder = xlContext
.MergeCells = False
End With
End With 'ws
End Sub
Function FWorkbookName(mStr As String)
Dim fstr As Variant, fstrB As Variant
Dim FWstr As String
'Debug.Print mStr
fstr = Split(mStr, ";")
fstrB = Split(fstr(2), "\")
FWstr = fstrB(UBound(fstrB, 1))
FWorkbookName = FWstr
End Function
Function FWorkbookPath(mStr As String)
Dim fstr As Variant, fstrB As Variant
Dim FWstr As String
'Debug.Print mStr
fstr = Split(mStr, ";")
FWstr = Right(fstr(3), Len(fstr(3)) - 11)
FWorkbookPath = FWstr
End Function
Public Function GetRange(wbk As Workbook, ByVal sListName As String) As String
Dim oListObject As ListObject
'Dim wbk As Workbook
Dim WS As Worksheet
'Set wb = ThisWorkbook
sListName = Replace(sListName, " ", "_")
sListName = "Tableau_" & sListName
For Each WS In wbk.Sheets
For Each oListObject In WS.ListObjects
If oListObject.Name = sListName Then
GetRange = WS.Name & vbCrLf & "[" & Replace(oListObject.Range.Address, "$", "") & "]"
Exit Function
End If
Next oListObject
Next WS
Dim conn As WorkbookConnection
'For Each conn In wbk.Connections
' Debug.Print conn.Name
'Next conn
End Function
Any ideas?
IG Data analyst
edit 1
drop box photo link (no account needed) there you can see the resulting screen. It shows in yellow the worksheet name and the corresponding table query. The stakeholder wants things to exactly match (the worksheet with the corresponding query).
enter image description here
The reason for the connection not matching the worksheet name that appears on the row is that the person who first worked on this workbook first changed many times over queries after creating query tables.

Export sheet as CSV, add new column with header and insert workbook name in all the cells

I want to create a macro that copies a sheet called "Week" from my workbook, deletes the first row, adds a new column (farthest to the left), assigns it the header "Department" and assigns it a fixed value. The fixed value should be the name of the CSV file. The name can be found on the front page in cell G6. I don't want the fixed value to be copied all the way down in the first column. I want it to be copied until there isn't any value in any of the columns to the right of the first column. Currently I've tried just comparing it to the second column (column B). I get the message:
Run-time error '424':
Object required
and is referring back to:¨
If InStr(1, thiswork.Sheets(ActiveSheet.Name).Range("$B$" & X), "") > 0 Then
This is my code:
Sub Export_pb_uge()
Dim MyPath As String
Dim MyFileName As String
MyPath = "C:mypath1"
MyFileName = Sheets("Front_Page").Range("g6").Value
Application.ScreenUpdating = False
Application.DisplayAlerts = False
If Not Right(MyPath, 1) = "\" Then MyPath = MyPath & "\"
If Not Right(MyFileName, 4) = ".csv" Then MyFileName = MyFileName & ".csv"
Sheets("PB_uge").Visible = True
Sheets("PB_uge").Copy
Rows(1).EntireRow.Delete
With target_sheet
Range("A1").EntireColumn.Insert
Range("A1").Value = "Department"
End With
If ThisWorkbook.Sheets(ActiveSheet.Name).FilterMode Then ThisWorkbook.Sheets(ActiveSheet.Name).ShowAllData
lRow = ThisWorkbook.Sheets(ActiveSheet.Name).Cells(Rows.Count, "B").End(xlUp).Row
For X = 1 To lRow
If InStr(1, thiswork.Sheets(ActiveSheet.Name).Range("$B$" & X), "") > 0 Then
target_sheet.Range("$A$" & X) = ActiveSheet.Name
End If
Next
With ActiveWorkbook
.SaveAs Filename:= _
MyPath & MyFileName, _
FileFormat:=xlCSV, _
CreateBackup:=False, _
Local:=True
.Close False
End With
Sheets("Week").Visible = False
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
Well spotted gazzz0x2z, however I would also declare and set target_sheet
Dim target_sheet As Worksheet
Set target_sheet = ActiveSheet ' or for example Sheets("sheet1")
With target_sheet
Range("A1").EntireColumn.Insert
Range("A1").Value = "Department"
End With
If ThisWorkbook.Sheets(ActiveSheet.Name).FilterMode Then ThisWorkbook.Sheets (ActiveSheet.Name).ShowAllData
lRow = ThisWorkbook.Sheets(ActiveSheet.Name).Cells(Rows.Count, "B").End(xlUp).Row
For X = 1 To lRow
If InStr(1, ThisWorkbook.Sheets(ActiveSheet.Name).Range("$B$" & X), "") > 0 Then
target_sheet.Range("$A$" & X) = ActiveSheet.Name
End If
Next
Try :
If InStr(1, ThisWorkbook.Sheets(ActiveSheet.Name).Range("$B$" & X), "") > 0 Then
Seems like, for some reason, you've lost 4 letters.
I found the answer to be:
Sub Export_PB_uge()
Dim pb_uge As Worksheet
Dim myPath As String
Dim MyFileName As String
Dim x As Long
Dim wsCSV As Worksheet
myPath = "C:mypath1"
MyFileName = Sheets("Front_Page").Range("g6").Value
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
If Not Right(myPath, 1) = "\" Then myPath = myPath & "\"
If Not Right(MyFileName, 4) = ".csv" Then MyFileName = MyFileName & ".csv"
With ThisWorkbook.Sheets("PB_uge")
If .FilterMode Then pb_uge.ShowAllData
.Visible = True
.Copy
End With
Set wsCSV = ActiveWorkbook.Sheets(1)
With wsCSV
.Range("A1").EntireRow.Delete
.Range("A1").EntireColumn.Insert
.Range("A1").Value = "Department"
lRow = .Cells(Rows.Count, "C").End(xlUp).Row
.Range("A2:A" & lRow) = ThisWorkbook.Sheets("Front_Page").Range("g6").Value
.Parent.SaveAs Filename:= _
myPath & MyFileName, _
FileFormat:=xlCSV, _
CreateBackup:=False, _
Local:=True
.Parent.Close False
End With
ThisWorkbook.Sheets("PB_uge").Visible = False
Application.EnableEvents = True
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Application.DisplayAlerts = True
MsgBox "CSV saved at " & myPath & MyFileName, vbInformation
End Sub

Statistical Quality Control Macro Changing parameters to a determined std.dev

I found a macro online that creates a Statistical Quality Control chart online. So I have a .Csv file that looks like an excel sheet. I use the macro, so I have to select the data points. Then I have to select the labels, and then it gets plotted.
So instead of calculating the standard deviation from the selected data as my macro does, I want it to calculate the Upper limits and Lower limits from a set Standard deviation. Which is in the cell "F3". I have tried creating a variant where "stddev=Range("F3").value" But when I included it in my macro, the data was scattered and my labels on the right were not showing up as they were before. I will specify , where in the code that I think the problem is lying.
Here is the full code for creating the Quality control chart:
Option Explicit
Public Function GetRange(box_message As String) As Range
Set GetRange = Nothing
On Error Resume Next
Set GetRange = Application.InputBox(box_message, "Select Range", Selection.Address, , , , , 8)
End Function
Public Function IsNotOk(ByVal rng As Range) As Boolean 'TO CHECK IF A GIVEN RANGE IS BLANK
IsNotOk = True
On Error GoTo if_error_occured:
If rng.Rows.Count > 0 And rng.Columns.Count = 1 Then IsNotOk = False
if_error_occured:
If Err.Number Then IsNotOk = True
End Function
Public Function check_if_numeric(rng As Range) As Boolean
Dim cel As Range
check_if_numeric = True
For Each cel In rng.Cells
If Not (Application.WorksheetFunction.IsNumber(cel.Value)) Then check_if_numeric = False
Next cel
End Function
Sub Make_Control_Chart()
Dim data_values As Range
Dim chart_labels As Range
Dim range_selected_before As Range
Dim got_label_range As Boolean
Dim got_value_range As Boolean
Dim bActivate As Boolean
Dim myChtObj As ChartObject
Dim plot_series, MyNewSrs As Series
Dim series_label As String
Dim number_of_control_limits As Integer
Dim standard_deviation As Integer
Dim data_str As String
Dim avg_str As String
Dim stddev As Variant
On Error GoTo if_error_occured: 'GOTO THE END OF THE PROGRAM
stddev = Range("F3").Value
'GET RANGE FOR DATA VALUES
bActivate = False ' True to re-activate the input range
Set data_values = GetRange("Please select the range containing the DATA POINTS" & Chr(13) & "(press select a single column)")
If IsNotOk(data_values) Then
MsgBox "Incorrect Input Data !"
End
ElseIf Not (check_if_numeric(data_values)) Then
MsgBox "Incorrect Input Data !"
End
End If
'GET RANGE FOR CHART X-AXIS LABELS
got_label_range = True ' True to re-activate the input range
Set chart_labels = GetRange("Please select the range containing the LABELS" & Chr(13) & "(press ESC if no labels available)")
If IsNotOk(chart_labels) Then
got_label_range = False
End If
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
'LETS CREATE THE CHART NOW
Set myChtObj = ActiveSheet.ChartObjects.Add(Left:=300, Width:=450, Top:=25, Height:=300)
myChtObj.Chart.ChartType = xlLineMarkers
'REMOVE ALL UNWANTED SERIES FROM CHART, IF ANY
For Each MyNewSrs In myChtObj.Chart.SeriesCollection ' myChtObj.Chart.SeriesCollection
MyNewSrs.Delete
Next MyNewSrs
Set MyNewSrs = Nothing
If got_label_range Then 'IF WE HAVE THE LABEL RANGE
'ADD NEW SERIES
Set MyNewSrs = myChtObj.Chart.SeriesCollection.NewSeries
With MyNewSrs
.Name = "PLOT"
.Values = data_values
.XValues = chart_labels.Value
End With
Else
Set MyNewSrs = myChtObj.Chart.SeriesCollection.NewSeries
With MyNewSrs
.Name = "PLOT"
.Values = data_values
End With
End If
'FORMAT THE PLOT SERIES
Set plot_series = MyNewSrs
With MyNewSrs
.Border.ColorIndex = 1
.MarkerBackgroundColorIndex = 2
.MarkerForegroundColorIndex = xlAutomatic
.MarkerStyle = xlCircle
.Smooth = False
.MarkerSize = 5
.Shadow = False
End With
Set MyNewSrs = Nothing
'CREATE NAMED RANGE FOR THE DATA VALUES, AVERAGE, LOWER AND UPPER CONTROL LIMITS
data_str = Application.WorksheetFunction.Substitute(myChtObj.Name, " ", "") & "_data_values"
avg_str = "roundup(average(" & Application.WorksheetFunction.Substitute(myChtObj.Name, " ", "") & "_data_values" & "),2)"
'HERE THE LIMITS ARE SET AND THE ORIGINAL CODE IS SET IN THERE WHERE IT WORKS ON A SET OF DATA POINTS, HOWEVER WHEN I TRY TO CHANGE IT TO JUST "1*stddev,3" the data gets all scattered. I'M WONDERING WHY THE DATA IS BEING SCATTERED?
ActiveWorkbook.Names.Add Name:=Application.WorksheetFunction.Substitute(myChtObj.Name, " ", "") & "_data_values", RefersToR1C1:=data_values
ActiveWorkbook.Names.Add Name:=Application.WorksheetFunction.Substitute(myChtObj.Name, " ", "") & "_AVG", RefersToR1C1:="=" & avg_str & ""
ActiveWorkbook.Names.Add Name:=Application.WorksheetFunction.Substitute(myChtObj.Name, " ", "") & "_LCL1", RefersToR1C1:="=" & avg_str & "- roundup(1*stdev(" & data_str & "),3)"
ActiveWorkbook.Names.Add Name:=Application.WorksheetFunction.Substitute(myChtObj.Name, " ", "") & "_LCL2", RefersToR1C1:="=" & avg_str & "- roundup(2*stdev(" & data_str & "),3)"
ActiveWorkbook.Names.Add Name:=Application.WorksheetFunction.Substitute(myChtObj.Name, " ", "") & "_LCL3", RefersToR1C1:="=" & avg_str & "- roundup(3*stdev(" & data_str & "),3)"
ActiveWorkbook.Names.Add Name:=Application.WorksheetFunction.Substitute(myChtObj.Name, " ", "") & "_UCL1", RefersToR1C1:="=" & avg_str & "+ roundup(1*stdev(" & data_str & "),3)"
ActiveWorkbook.Names.Add Name:=Application.WorksheetFunction.Substitute(myChtObj.Name, " ", "") & "_UCL2", RefersToR1C1:="=" & avg_str & "+ roundup(2*stdev(" & data_str & "),3)"
ActiveWorkbook.Names.Add Name:=Application.WorksheetFunction.Substitute(myChtObj.Name, " ", "") & "_UCL3", RefersToR1C1:="=" & avg_str & "+ roundup(3*stdev(" & data_str & "),3)"
The code for formatting and creating the lines on the chart:
'ADD THE LINE FOR AVERAGE
Set MyNewSrs = myChtObj.Chart.SeriesCollection.NewSeries
With MyNewSrs
.Name = "AVG = "
.Values = "='" & ActiveSheet.Name & "'!" & Application.WorksheetFunction.Substitute(myChtObj.Name, " ", "") & "_AVG"
.ChartType = xlXYScatter
'.ErrorBar Direction:=xlX, Include:=xlNone, Type:=xlFixedValue, Amount:=10000
'.ErrorBar Direction:=xlX, Include:=xlUp, Type:=xlFixedValue, Amount:=20
.ErrorBar Direction:=xlX, Include:=xlPlusValues, Type:=xlFixedValue, Amount:=data_values.Rows.Count
.MarkerBackgroundColorIndex = xlAutomatic
.MarkerForegroundColorIndex = xlAutomatic
.MarkerStyle = xlNone
.Smooth = False
.MarkerSize = 5
.Shadow = False
With .Border
.Weight = xlHairline
.LineStyle = xlNone
End With
'With .ErrorBars.Border
' .LineStyle = xlContinuous
' .ColorIndex = 3
' .Weight = xlThin
'End With
End With
Set MyNewSrs = Nothing
'ADD UPPER AND LOWER CONTROL LIMITS
For number_of_control_limits = 1 To 3
For standard_deviation = -1 To 1 Step 2
Select Case standard_deviation:
Case -1: series_label = "LCL"
Case 1: series_label = "UCL"
End Select
Set MyNewSrs = myChtObj.Chart.SeriesCollection.NewSeries
With MyNewSrs
.Name = series_label & number_of_control_limits & " ="
.Values = "='" & ActiveSheet.Name & "'!" & Application.WorksheetFunction.Substitute(myChtObj.Name, " ", "") & "_" & series_label & number_of_control_limits
.ChartType = xlXYScatter
.ErrorBar Direction:=xlX, Include:=xlPlusValues, Type:=xlFixedValue, Amount:=data_values.Rows.Count
End With
MyNewSrs.ErrorBar Direction:=xlX, Include:=xlPlusValues, Type:=xlFixedValue, Amount:=data_values.Rows.Count
Select Case number_of_control_limits:
Case 1:
With MyNewSrs.ErrorBars.Border
.LineStyle = xlGray25
.ColorIndex = 15
.Weight = xlHairline
End With
Case 2:
With MyNewSrs.ErrorBars.Border
.LineStyle = xlGray25
.ColorIndex = 57
.Weight = xlHairline
End With
Case 3:
With MyNewSrs.ErrorBars.Border
.LineStyle = xlGray75
.ColorIndex = 3
.Weight = xlHairline
End With
End Select
MyNewSrs.ErrorBars.EndStyle = xlNoCap
With MyNewSrs
With .Border
.Weight = xlHairline
.LineStyle = xlNone
End With
.MarkerBackgroundColorIndex = xlAutomatic
.MarkerForegroundColorIndex = xlAutomatic
.MarkerStyle = xlNone
.Smooth = False
.MarkerSize = 5
.Shadow = False
End With
Set MyNewSrs = Nothing
Next standard_deviation
Next number_of_control_limits
myChtObj.Chart.ApplyDataLabels AutoText:=True, LegendKey:=False, _
HasLeaderLines:=False, ShowSeriesName:=True, ShowCategoryName:=False, _
ShowValue:=True, ShowPercentage:=False, ShowBubbleSize:=False, Separator:=" "
'OFFSET THE LABELS
For Each MyNewSrs In myChtObj.Chart.SeriesCollection
With MyNewSrs.Points(1).DataLabel
.Left = 400
End With
Next MyNewSrs
'LETS FORMAT THE CHART
With myChtObj
With .Chart.Axes(xlCategory)
.MajorTickMark = xlNone
.MinorTickMark = xlNone
.TickLabelPosition = xlNextToAxis
End With
With .Chart.Axes(xlValue)
.MajorTickMark = xlOutside
.MinorTickMark = xlNone
.TickLabelPosition = xlNextToAxis
End With
With .Chart.ChartArea.Border
.Weight = 1
.LineStyle = 0
End With
With .Chart.PlotArea.Border
.ColorIndex = 1
.Weight = xlThin
.LineStyle = xlContinuous
End With
With .Chart.PlotArea.Interior
.ColorIndex = 2
.PatternColorIndex = 1
.Pattern = xlSolid
End With
With .Chart.ChartArea.Font
.Name = "Arial"
.Size = 8
.Strikethrough = False
.Superscript = False
.Subscript = False
.OutlineFont = False
.Shadow = False
.Underline = xlUnderlineStyleNone
.ColorIndex = xlAutomatic
.Background = xlAutomatic
End With
With .Chart
.HasTitle = False
.Axes(xlCategory, xlPrimary).HasTitle = False
.Axes(xlValue, xlPrimary).HasTitle = True
.HasTitle = True
.ChartTitle.Characters.Text = "Control Chart"
.ChartTitle.Left = 134
.Axes(xlValue, xlPrimary).AxisTitle.Characters.Text = "Observations"
End With
With .Chart.Axes(xlCategory).TickLabels
.Alignment = xlCenter
.Offset = 100
.ReadingOrder = xlContext
.Orientation = xlHorizontal
End With
End With
myChtObj.Chart.Legend.Delete
myChtObj.Chart.PlotArea.Width = 310
myChtObj.Chart.Axes(xlValue).MajorGridlines.Delete
myChtObj.Chart.Axes(xlValue).CrossesAt = myChtObj.Chart.Axes(xlValue).MinimumScale
myChtObj.Chart.ChartArea.Interior.ColorIndex = xlAutomatic
myChtObj.Chart.ChartArea.AutoScaleFont = True
'DELETE THE LABELS FOR THE ACTUAL DATA SERIES
plot_series.DataLabels.Delete
Set plot_series = Nothing
if_error_occured:
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
If Err.Number Then z_delete_all_named_range
End Sub
Sub z_delete_all_named_range()
Dim nam As Name
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
For Each nam In ActiveWorkbook.Names
nam.Delete
Next nam
End Sub
Compiled but not tested:
Sub Make_Control_Chart()
Dim data_values As Range
Dim chart_labels As Range
Dim range_selected_before As Range
Dim got_label_range As Boolean
Dim got_value_range As Boolean
Dim bActivate As Boolean
Dim myChtObj As ChartObject
Dim plot_series, MyNewSrs As Series
Dim series_label As String
Dim number_of_control_limits As Integer
Dim standard_deviation As Integer
Dim data_str As String
Dim avg_str As String
Dim stddev As Variant
Dim wb As Workbook, sCht As String, i As Long
Set wb = ActiveWorkbook
'On Error GoTo if_error_occured: 'GOTO THE END OF THE PROGRAM
stddev = Range("F3").Value
'GET RANGE FOR DATA VALUES
bActivate = False ' True to re-activate the input range
Set data_values = GetRange("Please select the range containing the DATA POINTS" & _
Chr(13) & "(press select a single column)")
If IsNotOk(data_values) Then
MsgBox "Incorrect Input Data !"
Exit Sub 'not End!
ElseIf Not (check_if_numeric(data_values)) Then
MsgBox "Incorrect Input Data !"
Exit Sub 'not End!
End If
'GET RANGE FOR CHART X-AXIS LABELS
got_label_range = True ' True to re-activate the input range
Set chart_labels = GetRange("Please select the range containing the LABELS" & _
Chr(13) & "(press ESC if no labels available)")
If IsNotOk(chart_labels) Then
got_label_range = False
End If
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
'LETS CREATE THE CHART NOW
Set myChtObj = ActiveSheet.ChartObjects.Add(Left:=300, Width:=450, _
Top:=25, Height:=300)
myChtObj.Chart.ChartType = xlLineMarkers
'REMOVE ALL UNWANTED SERIES FROM CHART, IF ANY
For Each MyNewSrs In myChtObj.Chart.SeriesCollection
MyNewSrs.Delete
Next MyNewSrs
Set MyNewSrs = Nothing
'IF WE HAVE THE LABEL RANGE
'ADD NEW SERIES
Set MyNewSrs = myChtObj.Chart.SeriesCollection.NewSeries
With MyNewSrs
.Name = "PLOT"
.Values = data_values
If got_label_range Then
.XValues = chart_labels.Value
End If
End With
'FORMAT THE PLOT SERIES
Set plot_series = MyNewSrs
With MyNewSrs
.Border.ColorIndex = 1
.MarkerBackgroundColorIndex = 2
.MarkerForegroundColorIndex = xlAutomatic
.MarkerStyle = xlCircle
.Smooth = False
.MarkerSize = 5
.Shadow = False
End With
Set MyNewSrs = Nothing
'CREATE NAMED RANGE FOR THE DATA VALUES, AVERAGE, LOWER AND UPPER CONTROL LIMITS
sCht = sCht
data_str = sCht & "_data_values"
avg_str = "roundup(average(" & sCht & "_data_values" & "),2)"
wb.Names.Add Name:=sCht & "_data_values", RefersToR1C1:=data_values
wb.Names.Add Name:=sCht & "_AVG", RefersToR1C1:="=" & avg_str & ""
For i = 1 To 3
wb.Names.Add Name:=sCht & "_LCL" & i, _
RefersToR1C1:="=" & avg_str & "- roundup(" & i & "*" & stddev & ",3)"
wb.Names.Add Name:=sCht & "_UCL" & i, _
RefersToR1C1:="=" & avg_str & "+ roundup(" & i & "*" & stddev & ",3)"
Next i
End Sub
Public Function GetRange(box_message As String) As Range
On Error Resume Next
Set GetRange = Application.InputBox(box_message, "Select Range", Selection.Address, , , , , 8)
End Function
Public Function IsNotOk(ByVal rng As Range) As Boolean 'TO CHECK IF A GIVEN RANGE IS BLANK
IsNotOk = True
On Error GoTo if_error_occured:
If rng.Rows.Count > 0 And rng.Columns.Count = 1 Then IsNotOk = False
if_error_occured:
If Err.Number Then IsNotOk = True
End Function
Public Function check_if_numeric(rng As Range) As Boolean
Dim cel As Range, rv As Boolean
rv = True
For Each cel In rng.Cells
If Not (Application.WorksheetFunction.IsNumber(cel.Value)) Then
rv = False
Exit For
End If
Next cel
check_if_numeric = rv
End Function