Format datatable values in VBA - vba

Currently working on a vba script that makes charts automatically. I would like to add a datatable which is done using: .HasDataTable = True
However I would like to show the values of series as percentages. Currently the value is defined as a Double containing all the values but not the right formatting. Using Format() or FormatPercent() will give the right values but returned in a String. This works for the datatable but not for the chart itself since it doesn't recognize the values anymore.
My question comes down to whether it is possible to show the values as percentages in both the datatable and the chart? Without VBA it is easily done by formatting the data in the cells itself. The problem is that for formatting a String is returned but for the graph Integers or Doubles are needed.
Below is part of the code. If I dim Ratio as String and use FormatPercent() I get the requested formatting but then the values in Ratio ar no longer doubles so it doesn't give the required chart.
Dim Ratio() As Double
Dim labels() As String
ReDim Ratio(1 To Height)
ReDim labels(1 To Height)
For Each Column In sArray
labels(i) = Sheets(DataSheetName).Cells(LabelsRow, Column)
Ratio(i) = Math.Round(Sheets(DataSheetName).Cells(LabelsRow + 3, Column), 2)
i = i + 1
Next Column
Set myChtObj = Sheets(DrawSheetName).ChartObjects.Add(Left:=Left, Width:=Width, Top:=Top, Height:=HeightGraph)
Dim srsNew1 As Series
' Add the chart
With myChtObj.Chart
.ChartArea.Fill.Visible = False
.ChartArea.Border.LineStyle = xlNone
.PlotArea.Format.Fill.Solid
.PlotArea.Format.Fill.Transparency = 1
.HasTitle = True
.ChartTitle.text = Title
.HasLegend = False
.Axes(xlValue).TickLabels.NumberFormat = "0%"
.Axes(xlCategory, xlPrimary).HasTitle = False
'add data table
.HasDataTable = True
' Make Line chart
.ChartType = xlLine
' Add series
Set srsNew1 = .SeriesCollection.NewSeries
With srsNew1
.Values = Ratio
.XValues = labels
.Name = "Ratio"
.Interior.Color = clr3 'RGB(194, 84, 57)
End With
End With

Related

Excel Chart - How to draw discontinuous series in VBA without range reference

Excel 2010.
Issue : I need to plot a *single* *discontinuous* series in a XY-scatter chart *via VBA* without referencing a range in the sheet.
It is easy to achieve that when the Yvalues are laid-out in a sheet range, by inserting blank values at the discontinuities ; as long as one selects 'Show empty cells as: Gaps' in Select Data > Hidden and Empty Cells. Here is an example (the Series2 in red is the one that matters) :
So I was trying to reproduce the same via VBA :
Sub addDiscountinuousSingleSeries()
Dim vx As Variant, vy As Variant
Dim chrtObj As ChartObject, chrt As Chart, ser As Series
Set chrtObj = ActiveSheet.ChartObjects("MyChart"): Set chrt = chrtObj.Chart
Set ser = chrt.SeriesCollection.NewSeries
vx = Array(0.3, 0.3, 0.3, 0.7, 0.7, 0.7)
vy = Array(-1, 1, vbNullString, -1, 1, vbNullString)
'vy = Array(-1, 1, CVErr(xlErrNA), -1, 1, CVErr(xlErrNA)) 'doesn't work either
'vy = Range(RANGE_YVALUES_WITH_BLANK) 'this would work, but I do not want to reference a range
chrt.DisplayBlanksAs = xlNotPlotted 'VBA equivalent to 'Show empty cells as: Gaps'
With ser
ser.Name = "VBA Series"
.XValues = vx
.Values = vy
End With
End Sub
But the blank values in the vy array seems to be ignored and the two vertical bars are now connected, which I am trying to avoid (green series).
I know that I could delete the middle line programmatically, but in the real-life problem I am trying to solve it would not be the right solution (too complex, too slow).
My question : is there a way to specify the series' .Values array to get the expected behavior and get a gap between the two vertical green segments in vba (with only one series and no reference to a sheet range)?
You could just format the lines you don't want. Maybe not the prettiest way, but it'd achieve what your after.
ser.Points(3).Format.Line.Visible = msoFalse
ser.Points(4).Format.Line.Visible = msoFalse
ser.Points(6).Format.Line.Visible = msoFalse
Or:
For i = 1 To ser.Points.Count
If i <> 1 Then k = i - 1 Else k = i
If ser.Values(i) = 0 Or ser.Values(k) = 0 Then
ser.Points(i).Format.Line.Visible = msoFalse
End If
Next

How to add text to column headers in list box with multiple columns? [duplicate]

Is it possible to set up the headers in a multicolumn listbox without using a worksheet range as the source?
The following uses an array of variants which is assigned to the list property of the listbox, the headers appear blank.
Sub testMultiColumnLb()
ReDim arr(1 To 3, 1 To 2)
arr(1, 1) = "1"
arr(1, 2) = "One"
arr(2, 1) = "2"
arr(2, 2) = "Two"
arr(3, 1) = "3"
arr(3, 2) = "Three"
With ufTestUserForm.lbTest
.Clear
.ColumnCount = 2
.List = arr
End With
ufTestUserForm.Show 1
End Sub
Here is my approach to solve the problem:
This solution requires you to add a second ListBox element and place it above the first one.
Like this:
Then you call the function CreateListBoxHeader to make the alignment correct and add header items.
Result:
Code:
Public Sub CreateListBoxHeader(body As MSForms.ListBox, header As MSForms.ListBox, arrHeaders)
' make column count match
header.ColumnCount = body.ColumnCount
header.ColumnWidths = body.ColumnWidths
' add header elements
header.Clear
header.AddItem
Dim i As Integer
For i = 0 To UBound(arrHeaders)
header.List(0, i) = arrHeaders(i)
Next i
' make it pretty
body.ZOrder (1)
header.ZOrder (0)
header.SpecialEffect = fmSpecialEffectFlat
header.BackColor = RGB(200, 200, 200)
header.Height = 10
' align header to body (should be done last!)
header.Width = body.Width
header.Left = body.Left
header.Top = body.Top - (header.Height - 1)
End Sub
Usage:
Private Sub UserForm_Activate()
Call CreateListBoxHeader(Me.listBox_Body, Me.listBox_Header, Array("Header 1", "Header 2"))
End Sub
No. I create labels above the listbox to serve as headers. You might think that it's a royal pain to change labels every time your lisbox changes. You'd be right - it is a pain. It's a pain to set up the first time, much less changes. But I haven't found a better way.
I was looking at this problem just now and found this solution. If your RowSource points to a range of cells, the column headings in a multi-column listbox are taken from the cells immediately above the RowSource.
Using the example pictured here, inside the listbox, the words Symbol and Name appear as title headings. When I changed the word Name in cell AB1, then opened the form in the VBE again, the column headings changed.
The example came from a workbook in VBA For Modelers by S. Christian Albright, and I was trying to figure out how he got the column headings in his listbox :)
Simple answer: no.
What I've done in the past is load the headings into row 0 then set the ListIndex to 0 when displaying the form. This then highlights the "headings" in blue, giving the appearance of a header. The form action buttons are ignored if the ListIndex remains at zero, so these values can never be selected.
Of course, as soon as another list item is selected, the heading loses focus, but by this time their job is done.
Doing things this way also allows you to have headings that scroll horizontally, which is difficult/impossible to do with separate labels that float above the listbox. The flipside is that the headings do not remain visible if the listbox needs to scroll vertically.
Basically, it's a compromise that works in the situations I've been in.
There is very easy solution to show headers at the top of multi columns list box.
Just change the property value to "true" for "columnheads" which is false by default.
After that Just mention the data range in property "rowsource" excluding header from the data range and header should be at first top row of data range then it will pick the header automatically and you header will be freezed.
if suppose you have data in range "A1:H100" and header at "A1:H1" which is the first row then your data range should be "A2:H100" which needs to mention in property "rowsource" and "columnheads" perperty value should be true
Regards,
Asif Hameed
Just use two Listboxes, one for header and other for data
for headers - set RowSource property to top row e.g. Incidents!Q4:S4
for data - set Row Source Property to Incidents!Q5:S10
SpecialEffects to "3-frmSpecialEffectsEtched"
I like to use the following approach for headers on a ComboBox where the CboBx is not loaded from a worksheet (data from sql for example). The reason I specify not from a worksheet is that I think the only way to get RowSource to work is if you load from a worksheet.
This works for me:
Create your ComboBox and create a ListBox with an identical layout but just one row.
Place the ListBox directly on top of the ComboBox.
In your VBA, load ListBox row1 with the desired headers.
In your VBA for the action yourListBoxName_Click, enter the following code:
yourComboBoxName.Activate`
yourComboBoxName.DropDown`
When you click on the listbox, the combobox will drop down and function normally while the headings (in the listbox) remain above the list.
I was searching for quite a while for a solution to add a header without using a separate sheet and copy everything into the userform.
My solution is to use the first row as header and run it through an if condition and add additional items underneath.
Like that:
If lborowcount = 0 Then
With lboorder
.ColumnCount = 5
.AddItem
.Column(0, lborowcount) = "Item"
.Column(1, lborowcount) = "Description"
.Column(2, lborowcount) = "Ordered"
.Column(3, lborowcount) = "Rate"
.Column(4, lborowcount) = "Amount"
End With
lborowcount = lborowcount + 1
End If
With lboorder
.ColumnCount = 5
.AddItem
.Column(0, lborowcount) = itemselected
.Column(1, lborowcount) = descriptionselected
.Column(2, lborowcount) = orderedselected
.Column(3, lborowcount) = rateselected
.Column(4, lborowcount) = amountselected
End With
lborowcount = lborowcount + 1
in that example lboorder is the listbox, lborowcount counts at which row to add the next listbox item. It's a 5 column listbox. Not ideal but it works and when you have to scroll horizontally the "header" stays above the row.
Here's my solution.
I noticed that when I specify the listbox's rowsource via the properties window in the VBE, the headers pop up no problem. Its only when we try define the rowsource through VBA code that the headers get lost.
So I first went a defined the listboxes rowsource as a named range in the VBE for via the properties window, then I can reset the rowsource in VBA code after that. The headers still show up every time.
I am using this in combination with an advanced filter macro from a listobject, which then creates another (filtered) listobject on which the rowsource is based.
This worked for me
Another variant on Lunatik's response is to use a local boolean and the change event so that the row can be highlighted upon initializing, but deselected and blocked after a selection change is made by the user:
Private Sub lbx_Change()
If Not bHighlight Then
If Me.lbx.Selected(0) Then Me.lbx.Selected(0) = False
End If
bHighlight = False
End Sub
When the listbox is initialized you then set bHighlight and lbx.Selected(0) = True, which will allow the header-row to initialize selected; afterwards, the first change will deselect and prevent the row from being selected again...
Here's one approach which automates creating labels above each column of a listbox (on a worksheet).
It will work (though not super-pretty!) as long as there's no horizontal scrollbar on your listbox.
Sub Tester()
Dim i As Long
With Me.lbTest
.Clear
.ColumnCount = 5
'must do this next step!
.ColumnWidths = "70;60;100;60;60"
.ListStyle = fmListStylePlain
Debug.Print .ColumnWidths
For i = 0 To 10
.AddItem
.List(i, 0) = "blah" & i
.List(i, 1) = "blah"
.List(i, 2) = "blah"
.List(i, 3) = "blah"
.List(i, 4) = "blah"
Next i
End With
LabelHeaders Me.lbTest, Array("Header1", "Header2", _
"Header3", "Header4", "Header5")
End Sub
Sub LabelHeaders(lb, arrHeaders)
Const LBL_HT As Long = 15
Dim T, L, shp As Shape, cw As String, arr
Dim i As Long, w
'delete any previous headers for this listbox
For i = lb.Parent.Shapes.Count To 1 Step -1
If lb.Parent.Shapes(i).Name Like lb.Name & "_*" Then
lb.Parent.Shapes(i).Delete
End If
Next i
'get an array of column widths
cw = lb.ColumnWidths
If Len(cw) = 0 Then Exit Sub
cw = Replace(cw, " pt", "")
arr = Split(cw, ";")
'start points for labels
T = lb.Top - LBL_HT
L = lb.Left
For i = LBound(arr) To UBound(arr)
w = CLng(arr(i))
If i = UBound(arr) And (L + w) < lb.Width Then w = lb.Width - L
Set shp = ActiveSheet.Shapes.AddShape(msoShapeRectangle, _
L, T, w, LBL_HT)
With shp
.Name = lb.Name & "_" & i
'do some formatting
.Line.ForeColor.RGB = vbBlack
.Line.Weight = 1
.Fill.ForeColor.RGB = RGB(220, 220, 220)
.TextFrame2.TextRange.Characters.Text = arrHeaders(i)
.TextFrame2.TextRange.Font.Size = 9
.TextFrame2.TextRange.Font.Fill.ForeColor.RGB = vbBlack
End With
L = L + w
Next i
End Sub
You can give this a try. I am quite new to the forum but wanted to offer something that worked for me since I've gotten so much help from this site in the past. This is essentially a variation of the above, but I found it simpler.
Just paste this into the Userform_Initialize section of your userform code. Note you must already have a listbox on the userform or have it created dynamically above this code. Also please note the Array is a list of headings (below as "Header1", "Header2" etc. Replace these with your own headings. This code will then set up a heading bar at the top based on the column widths of the list box. Sorry it doesn't scroll - it's fixed labels.
More senior coders - please feel free to comment or improve this.
Dim Mywidths As String
Dim Arrwidths, Arrheaders As Variant
Dim ColCounter, Labelleft As Long
Dim theLabel As Object
[Other code here that you would already have in the Userform_Initialize section]
Set theLabel = Me.Controls.Add("Forms.Label.1", "Test" & ColCounter, True)
With theLabel
.Left = ListBox1.Left
.Top = ListBox1.Top - 10
.Width = ListBox1.Width - 1
.Height = 10
.BackColor = RGB(200, 200, 200)
End With
Arrheaders = Array("Header1", "Header2", "Header3", "Header4")
Mywidths = Me.ListBox1.ColumnWidths
Mywidths = Replace(Mywidths, " pt", "")
Arrwidths = Split(Mywidths, ";")
Labelleft = ListBox1.Left + 18
For ColCounter = LBound(Arrwidths) To UBound(Arrwidths)
If Arrwidths(ColCounter) > 0 Then
Header = Header + 1
Set theLabel = Me.Controls.Add("Forms.Label.1", "Test" & ColCounter, True)
With theLabel
.Caption = Arrheaders(Header - 1)
.Left = Labelleft
.Width = Arrwidths(ColCounter)
.Height = 10
.Top = ListBox1.Top - 10
.BackColor = RGB(200, 200, 200)
.Font.Bold = True
End With
Labelleft = Labelleft + Arrwidths(ColCounter)
End If
Next
This is a bummer. Have to use an intermediate sheet to put the data in so Excel knows to grab the headers. But I wanted that workbook to be hidden so here's how I had to do the rowsource.
Most of this code is just setting things up...
Sub listHeaderTest()
Dim ws As Worksheet
Dim testarr() As String
Dim numberOfRows As Long
Dim x As Long, n As Long
'example sheet
Set ws = ThisWorkbook.Sheets(1)
'example headers
For x = 1 To UserForm1.ListBox1.ColumnCount
ws.Cells(1, x) = "header" & x
Next x
'example array dimensions
numberOfRows = 15
ReDim testarr(numberOfRows, UserForm1.ListBox1.ColumnCount - 1)
'example values for the array/listbox
For n = 0 To UBound(testarr)
For x = 0 To UBound(testarr, 2)
testarr(n, x) = "test" & n & x
Next x
Next n
'put array data into the worksheet
ws.Range("A2").Resize(UBound(testarr), UBound(testarr, 2) + 1) = testarr
'provide rowsource
UserForm1.ListBox1.RowSource = "'[" & ws.Parent.Name & "]" & ws.Name & "'!" _
& ws.Range("A2").Resize(ws.UsedRange.Rows.Count - 1, ws.UsedRange.Columns.Count).Address
UserForm1.Show
End Sub
For scrolling, one idea is to create a simulated scroll bar which would shift the entire listbox left and right.
ensure the list box is set to full width so the horizontal scroll
bar doesn't appear (wider than the space available, or we wouldn't
need to scroll)
add a scroll bar control at the bottom but with .left and .width to
match the available horizontal space (so not as wide as the too-wide listbox)
calculate the distance you need to scroll as the difference between
the width of the extended list box and the width of the available
horizontal space
set .Min to 0 and .Max to the amount you need to scroll
set .LargeChange to make the slider-bar wider (I could only get it
to be half of the total span)
For this to work, you'd need to be able to cover left and right of the intended viewing space with a frame so that the listbox can pass underneath it and preserve any horizontal framing in the form. This turn out to be challenging, as getting a frame to cover a listbox seems not to work easily. I gave up at that point but am sharing these steps for posterity.
I found a way that seems to work but it can get messy the more complicated your code gets if you're dynamically clearing the range after every search or changing range.
Spreadsheet:
A B C
1 LName Fname
2 Smith Bob
set rng_Name = ws_Name.range("A1", ws_Name.range("C2").value
lstbx.Main.rowsource = rng_Name.Address
This will loads the Headers into the listbox and allow you to scroll.
Most importantly, if you're looping through your data and your range comes up empty, then your listbox won't load the headers correctly, so you will have to account for no "matches".
Why not just add Labels to the top of the Listbox and if changes are needed, the only thing you need to programmatically change are the labels.

How to assign XValues for excel chart using VBA

I have this VBA function for drawing charts in Excel 2013:
Sub DrawChart2(obj_worksheetTgt As Worksheet, ByVal XLabels As Range, ByVal DataValues As Range, ByVal chartTitle As String, a As Integer, b As Integer)
'
'obj_worksheetTgt - Object worksheet on which to be placed the chart
'XLabels - Data range for X labels
'DataValues - Data range for Y values
'chartTitle - Chart title
'a - left border position of chart in pixels
'b - top border position of chart in pixels
With obj_worksheetTgt.ChartObjects.Add(a, b, 900, 300) ' Left, Top, Width, Height
With .Chart
.ChartType = xlBarClustered
Set .SeriesCollection(1).XValues = XLabels ' Here is the error
Set .SeriesCollection(1).Values = DataValues
.Legend.Position = -4107
.HasTitle = True
.chartTitle.Text = chartTitle
.chartTitle.Font.Size = 12
With .Axes(1).TickLabels
.Font.Size = 8
.Orientation = 90
End With
End With
End With
End Sub
I call the function this way:
ChartsWorksheet = "Summary"
Queryname = "query1"
chartTitle = "Values"
With .Worksheets("LastDayData").ListObjects(Queryname)
Set chart_labels = .ListColumns(2).DataBodyRange
Set chart_values = .ListColumns(6).DataBodyRange
End With
Call DrawChart2(.Worksheets(ChartsWorksheet), chart_labels, chart_values, chartTitle, 10, 10)
And I receive an error:
Runtime Error '1004':
Invalid Parameter
When I click debug it marks the row "Set .SeriesCollection(1).XValues = XLabels" in the function above.
In the documentation is written:
The XValues property can be set to a range on a worksheet or to an
array of values, but it cannot be a combination of both
So it should be able to take the given range as values for XValues, but I can't understand why this error appears.
Before you can set the Values and XValues of a series, you will need to add the series first. This is simple to do using the SeriesCollection.NewSeries method as show below:
With ActiveSheet.ChartObjects.Add(a, b, 900, 300) ' Left, Top, Width, Height
With .Chart
.ChartType = xlBarClustered
' need to add the series before you can assign the values/xvalues
' calling the "NewSeries" method add one series each time you call it.
.SeriesCollection.NewSeries
' now that the series is added, you may assign (not set) the values/xvalues
.SeriesCollection(1).XValues = XLabels
.SeriesCollection(1).Values = DataValues
End With
End With
You cannot use named ranges for .XValues or .Values, but you can change the .Formula property by replacing the series formula
For more information on editing the series formula see http://peltiertech.com/change-series-formula-improved-routines/
Note of caution, there is a bug in Excel 2013 that prevents you from using named ranges starting with "R" or "C" when using VBA to change the series formula; see http://answers.microsoft.com/en-us/office/forum/office_2013_release-excel/named-range-use-in-chart-series-formulas-causes/c5a40317-c33f-4a83-84db-0eeee5c8827f/?auth=1&rtAction=1466703182593

Setting dates on X axis

I'm trying to create a chart in Excel VBA and am having problems getting the X-Axis to display the dates correctly; the code is below:
Function CreateChart()
Dim objChart As Chart
ReDim detached_price(detachedProps.count - 1) As Double
ReDim detached_date(detachedProps.count - 1) As Date
ReDim semi_price(semiProps.count - 1) As Double
ReDim semi_date(semiProps.count - 1) As Date
Dim minDate As Date
Dim maxDate As Date
minDate = Date
Dim detachedCount As Integer
detachedCount = 0
Dim semiCount As Integer
semiCount = 0
Set objChart = Charts.Add
With objChart
.HasTitle = True
.ChartTitle.Characters.Text = "Price Paid"
.ChartType = xlXYScatter
.Location xlLocationAsNewSheet
.Axes(xlCategory, xlPrimary).HasTitle = True
.Axes(xlCategory, xlPrimary).AxisTitle.Characters.Text = "Date"
.Axes(xlCategory, xlPrimary).CategoryType = xlTimeScale
.Axes(xlCategory, xlPrimary).TickLabels.NumberFormat = "yyyy"
.Axes(xlCategory, xlPrimary).MinimumScaleIsAuto = True
.Axes(xlCategory, xlPrimary).MaximumScaleIsAuto = True
For Each prop In properties
Select Case prop.PropertyType
Case "Detached"
detached_price(detachedCount) = prop.Amount
detached_date(detachedCount) = prop.SellDate
detachedCount = detachedCount + 1
Case "Semi-detached"
semi_price(semiCount) = prop.Amount
semi_date(semiCount) = prop.SellDate
semiCount = semiCount + 1
End Select
If prop.SellDate < minDate Then
minDate = prop.SellDate
End If
If prop.SellDate > maxDate Then
maxDate = prop.SellDate
End If
Next
.SeriesCollection.NewSeries
.SeriesCollection(DETACHED).Name = "Detached"
.SeriesCollection(DETACHED).Values = detached_price
.SeriesCollection(DETACHED).XValues = detached_date
.SeriesCollection.NewSeries
.SeriesCollection(SEMI).Name = "Semi-Detached"
.SeriesCollection(SEMI).Values = semi_price
.SeriesCollection(SEMI).XValues = semi_date
End With End Function
The properties variable in the For..Each loop is populated, and fills the arrays correctly.
However, although the Scatter Graph data points are shown, the dates on the axis all show 1900.
I tried adding the lines:
.Axes(xlCategory, xlPrimary).MinimumScale = CDbl(minDate)
.Axes(xlCategory, xlPrimary).MaximumScale = CDbl(maxDate)
Which showed the correct years along the axis, but now all the data points for both series have disappeared.
I've tried a few other things, but it's been purely on a trial and error basis.
The data is as follows
The resulting charts are:
Correct dates, no data points
Incorrect dates, but we have data points
Even though I disagree with their definition of "common" date format :q, I think that #chiliNUT is on to something. There seems to be some problem with the coercion of the date format.
If you change all of your Date type variables to Double or Long, it should work.
For example change
ReDim detached_date(detachedProps.count - 1) As Date
to
ReDim detached_date(detachedProps.count - 1) As Double
or
ReDim detached_date(detachedProps.count - 1) As Long
This way the dates are not converted into String by the XValues method. They are stored as date serial numbers and the axis routine is able to coerce them successfully into the local date format.
Whats happening in your code is the Date types are coerced to String by the XValues method and the axis rendering routine seems to be unable to coerce them back into dates properly.
I don't think it is actually related to the international settings as I tried it using dates like this:
1/01/2013
1/01/2014
1/01/2015
1/01/2016
1/01/2017
1/01/2018
1/01/2019
1/01/2020
1/01/2021
which works in either system.
I think its just a bug in the axis rendering routine where its unable to properly coerce strings into dates.
I would be interested to hear from others more knowledgeable than me.
Also, I'm curious about this:
.SeriesCollection.NewSeries
.SeriesCollection(DETACHED).Name = "Detached"
.SeriesCollection(DETACHED).Values = detached_price
.SeriesCollection(DETACHED).XValues = detached_date
How does it know which series to reference? Is DETACHED a constant you have defined elsewhere?
I would think this would be better:
with objChart.SeriesCollection.NewSeries
.Name = "Detached"
.Values = detached_price
.XValues = detached_date
end with

Excel 2010 Chart axis not shown up

I am converting a EXCEL 2003 application to EXCEL 2010. Data are shown up fine but the axis does not show any more. which function to show the axis with automatic scale?
For Example: If you plot the following series in an Excel Line Chart. [0.22,0.33,0.44,0.55,0.66,0.77,0.88,0.99,1.1,1.21,1.32,1.43,1.54,1.65,1.76,1.87,1.98,2.09,2.2] Excel determines that the y-axis values should be [0,0.5,1,1.5,2,2.5] [How does Excel determine the axis values for charts?1. How to make the y-axis with the automatic values [0,0.5,1,1.5,2,2.5] shown in the chart?
Thanks
Updated with related codes -
With ActiveChart
.SeriesCollection(2).Select
'.SeriesCollection(2).AxisGroup = 2
.HasTitle = True
.ChartTitle.Text = OutputTitle & Chr(10) & ChartTitle2
.Axes(xlValue).HasTitle = True
.Axes(xlValue).AxisTitle.Text = AxisTitle1
.Axes(xlValue).AxisTitle.Font.Bold = False
.HasAxis(Excel.XlAxisType.xlCategory, Excel.XlAxisGroup.xlPrimary) = True
.Export Filename:=ExportFile, FilterName:="GIF"
End with
If I uncomment '.SeriesCollection(2).AxisGroup = 2, I will get the y axis to show but the x axis labels are messed up with mismatch with the Values.
Current chart -
Desired chart with scaled axis shown -
To make sure the axis is on use this:
With xlApp.ActiveChart
.HasAxis(Excel.XlAxisType.xlCategory, Excel.XlAxisGroup.xlPrimary) = True
End With
Range values are automatic unless otherwise specified like this:
' Set Axis Scales
With xlApp.Charts("Chart Name").Axes(2)
.MinimumScale = 100
.MaximumScale = 2000
.MajorUnit = 1000
.MinorUnit = 100
End With
Just to be a little more complete try explicitly addressing each value and category and see if that helps.
With xlApp.ActiveChart
.SeriesCollection(1).XValues = "='sheet name'!R21C4:R46C4"
.SeriesCollection(1).Values = "='sheet name'!R21C5:R46C5"
.SeriesCollection(1).Name = "='series name'"
.SeriesCollection(1).axisgroup = Excel.XlAxisGroup.xlPrimary
.HasAxis(Excel.XlAxisType.xlCategory, Excel.XlAxisGroup.xlPrimary) = True
.HasAxis(Excel.XlAxisType.xlValue, Excel.XlAxisGroup.xlPrimary) = True
.Axes(Excel.XlAxisType.xlCategory, Excel.XlAxisGroup.xlPrimary).HasTitle = True
.Axes(Excel.XlAxisType.xlCategory, Excel.XlAxisGroup.xlPrimary).AxisTitle.Characters.Text = "x axis"
.Axes(Excel.XlAxisType.xlValue, Excel.XlAxisGroup.xlPrimary).HasTitle = True
.Axes(Excel.XlAxisType.xlValue, Excel.XlAxisGroup.xlPrimary).AxisTitle.Characters.Text = "y axis"
End With
I see your axes group is set to 2, are you using dual axis?
Set it like this:
.SeriesCollection(2).axisgroup = Excel.XlAxisGroup.xlPrimary
*Edit*
To set autoscale on the axis:
.Axes(xlValue).MinimumScaleIsAuto = True
.Axes(xlValue).MaximumScaleIsAuto = True
.Axes(xlValue).MinorUnitIsAuto = True
.Axes().MajorUnitIsAuto = True
.Axes().DisplayUnit = xlHundreds