Chart: Show more value descriptions on X-Axis - vb.net

I'm showing a Chart to the user which has one chart area with a line chart. On this, I got, for example, one line. This line has about 200 values. Those values do all have a description (e.g. "01.01.2013", "05.02.2013" and so on).
When the Chart is shown, I can only see two descriptions, even if there would be space for much more descriptions. The line gets displayed correctly, but there are only two points described.
I rotated the Text vertically so there is more space, but this didn't help. If I display less values (5 or 10), the descriptions get shown correctly.
This is how it actually looks like (the descriptions are actually Strings, not Dates).
Thank you for your help!
EDIT: My Code:
chart.ChartAreas(0).AxisY.Maximum = 6
chart.ChartAreas(0).AxisY.Minimum = 1
chart.ChartAreas(0).AxisX.LabelStyle.Angle = -90
chart.Series.Clear()
chart.ChartAreas(0).AxisY.StripLines.Clear()
Dim myStripLine1 as new StripLine()
myStripLine1.IntervalOffset = 4
chart.ChartAreas(0).AxisY.StripLines.add(myStripLine1)
'now adding all series
chart.Series.Add("Chemie") 'just to take the example in the image above
chart.Series(chart.Series.Count - 1).ChartType = DataVisualization.Charting.SeriesChartType.Line
chart.Series(chart.Series.Count - 1).BorderWidth = 4
'now adding quite much values (on every date, every Serie has a value)
chart.Series(chart.Series.Count - 1).Points.AddXY("01.03.2011", 4.9)
On every date, a new point gets entered for all series, but only those points where they have important values get highlighted. Those values between are calculated mathematically.
One example to explain this: I got two series, one has two values (6 and 4) on point "01.01.2013" and "03.01.2013". The other series has 3 values (4,6,5.5) on "01.01.2013","02.01.2013" and "03.01.2013". When I just display them, the first series will end at the second date, even if there was a value for the third date. I solved this by filling a dummy value at the first series with date "02.01.2013" which is just the average at this point (=5). This point simply does not get highlighted with a marker bullet. This is how I draw my graph.
EDIT2:
After Skippy's answer and comment, my new trial. The variable MainForm.grades is a Dictionary(Of Integer,Dictionary(Of String, String)) which contains around 150 grades
Dim subjects As New Dictionary(Of Integer, ArrayList)
Dim allgrades As New ArrayList
For Each grade In MainForm.grades
Dim cD As New Dictionary(Of String, String)
cD.Add("SUBJECTID", grade.Value("SUBJECTID"))
cD.Add("GRADE", grade.Value("GRADE"))
cD.Add("DATE", grade.Value("DATE"))
allgrades.Add(cD)
Next
cht_main.ChartAreas(0).AxisX.IntervalType = DateTimeIntervalType.Days
cht_main.ChartAreas(0).AxisX.LabelStyle.Angle = -90
Dim gradesDateSorter = New gradesDateSorter()
allgrades.Sort(gradesDateSorter)
For Each grade In allgrades
If Not subjects.ContainsKey(Integer.Parse(grade("SUBJECTID"))) Then
subjects.Add(Integer.Parse(grade("SUBJECTID")), New ArrayList)
End If
Dim gradeDict As New Dictionary(Of String, String)
gradeDict.Add("DATE", grade("DATE"))
gradeDict.Add("GRADE", grade("GRADE"))
subjects(Integer.Parse(grade("SUBJECTID"))).Add(gradeDict)
Next
For Each subject In subjects
'adding serie
cht_main.Series.Add(MainForm.subjects(subject.Key)("NAME"))
cht_main.Series(cht_main.Series.Count - 1).ChartType = DataVisualization.Charting.SeriesChartType.Line
cht_main.Series(cht_main.Series.Count - 1).BorderWidth = 4
'cht_main.Series(cht_main.Series.Count - 1).IsXValueIndexed = True
For Each grade In subject.Value
cht_main.Series(cht_main.Series.Count - 1).Points.AddXY(Date.Parse(grade("DATE")), Double.Parse(grade("GRADE")))
Next
Next
On the 5th last row I commented IsXValueIndexed=True because when I activated it, the chart gets generated with a big red error cross.
SOLUTION
Setting the Interval on the X-Axis does the trick!
chart.ChartAreas(0).AxisX.Interval = 1
Solution by Skippy

Yes I agree with Michael. I can only add to the explanation at this point.
By setting your interval:
myStripLine1.IntervalOffset = 4
You are guaranteeing that your X-axis values will be plotted only, at frequency of 4 " generic x-axis" values:
Setting this to vale to 1 will give a value for every x-axis value, that is incremented as a whole number (in this case days)
chart.ChartAreas(0).AxisX.Interval = 1
And to declare the x-axis values to type:
DateTimeIntervalType.Days
'Declaration
Public Sub Add( _
labelsStep As Double, _
intervalType As DateTimeIntervalType, _
format As String _
)
End Sub
chart.ChartAreas(0).AxisX.IntervalType = DateTimeIntervalType.Days
'which as shown in Michael's answer is parsed to string.
Dim format as String = "MM.dd.yyyy"
Dim actualDate as Date = Date.ParseExact(yourDate, format)
As mentioned by Michael in his comment.
By setting the
mySeries.XValueIndexed = True
Every indexed X-axis value will be plotted.
As explained in the following quote, with the link provided.
Each data point in a series has X and Y values that determine its position in the plotting area. With some charts, the X value of points is not important, and does not have to be provided. In this case, the point positions in the plotting area are determined only by their point index (i.e. their location in the Points collection) and their Y values.
When X values are "indexed", the data point index, not a point's X value, is used to determine the position of points along the categorical (X) axis. For example in Figure 1 below, two charts are shown displaying the same data. However, the first chart uses non-indexed X values, therefore the X values of those points determine their location along the x-axis. The second chart is indexed, therefore its point indices are used to determine their position along the x-axis. In this case the X values are only used for the axis labels, and nothing more.
http://support2.dundas.com/onlinedocumentation/winchart2005/Data_IndexedXValues.html
I sourced my original information regarding intervals and interval offsets at the following site:
http://support2.dundas.com/Default.aspx?article=705
Here it discusses datatype and addresses your issue of highlighted values.
On every date, a new point gets entered for all series, but only those points where they have important values get highlighted
For example, assume you wish to create a re-occurring StripLine to highlight weekends. You set the interval to 7 and its type to Days. Since the first point is Sunday you set the IntervalOffset to 6 (to mean the 6th day of the week) and its type to Days. The resulting chart does not show the first StripLine.
This is a an explanation for setting the interval.
A good rule of thumb to follow when using the Interval and IntervalOffset properties of the Chart is that the IntervalOffset should be a lower interval magnitude than the Interval (ie. Interval Days / IntervalOffset Hours, Interval Years / IntervalOffset Months, etc.).
I have added these sources:
For your reference
To show I have, also, done my research after ascertaining the problem, as stated in my comments above.
Florian, can you pls show the code for the labels, properties etc of the x-axis? – yvytty yesterday
Did you ever consider 3rd party plotting components, such as ZedGraph ? Most likely such little caveats are already covered there. Give it a shot! – Neolisk yesterday
In response to ZedGraph I advised:
And: After viewing your code
Hi can I clarify, you WANT to plot values daily? I think I have your solution, just need clarification, you have all the tools within vb.net
#yvytty, nope, the dates do not have to be daily, there can also be no value for a long time and I don't want a big span in my chart where no data is. Actually, I could also write some sample text at the X axis values, the dates are only confusing. The main problem is that the VB chart somehow calculates a very big margin on those descriptions at the X axis
It doesn't show that you have formatted your date and date string. There also needs to be taken into account, that you are not using the en-US date format (I'm in Australia, so we have the same format as you). The default date type is for en-US.
Please refer to DateTime.ParseExact Method
http://msdn.microsoft.com/en-us/library/system.datetime.parseexact.aspx
I have taken snippets from MSDN.
Dim dateString, format As String
Dim result As Date
Dim provider As CultureInfo = CultureInfo.InvariantCulture
Parse date and time with custom specifier.
dateString = "Sun 15 Jun 2008 8:30 AM -06:00"
format = "ddd dd MMM yyyy h:mm tt zzz"
result = Date.ParseExact(dateString, format, provider)
See link:
http://msdn.microsoft.com/en-us/library/w2sa9yss.aspx
The DateTime.ToString(IFormatProvider) method returns the string representation of a date and time value using the short date and long time pattern of a specific culture. The following example uses the DateTime.ToString(IFormatProvider) method to display the date and time using the short date and long time pattern for the fr-FR culture.
Dim date1 As Date = #3/1/2008 7:00AM#
Console.WriteLine(date1.ToString(System.Globalization.CultureInfo.CreateSpecificCulture("fr-FR")))
' Displays 01/03/2008 07:00:00
Please see this link:
http://msdn.microsoft.com/en-us/library/system.datetime.aspx
So it should go, something like this:
'note
Imports System.Globalization
Dim format as String = "dd.MM.yyyy"
Dim actualDate as Date = Date.ParseExact(yourDate, format, provider)
chart.ChartAreas(0).AxisX.LabelStyle.Format ="dd.MM.yyyy"
cht_main.ChartAreas(0).AxisX.IntervalType = DateTimeIntervalType.Days
cht_main.ChartAreas(0).AxisX.Interval = 1
ALSO:
Double.Parse(grade("GRADE")
'grade is not of type double

I think you should convert the string date representation to an actual datetime object before adding it to the chart.
I didn't test it but something like this: (where yourDate is the string you used to pass to the chart)
Dim format as String = "MM.dd.yyyy"
Dim actualDate as Date = Date.ParseExact(yourDate, format)
chart.Series(chart.Series.Count - 1).Points.AddXY(actualDate, 4.9)
The chart can manage datetime object instead of strings and it has special code that deals with dates. If you do this you you can adjust how it is displayed by formatting:
chart.ChartAreas(0).AxisX.LabelStyle.Format ="MM.dd.yyyy"
chart.ChartAreas(0).AxisX.Interval = 1
chart.ChartAreas(0).AxisX.IntervalType = DateTimeIntervalType.Days
If you wanted to only display every other day change the interval to 2

Related

How to convert Quarter years to other format

I have cells that can either contain time in this format:
1625 (16 for 2016 and 25 for week 25)
Or in this format
2016-Q2 (Q2 means quarter 2 if the year)
When converting I want quarters to be the mid week of the quarter
2016-Q1 = 1608
2016-Q2 = 1620
2016-Q3 = 1633
2016-Q4 = 1646
I dont want to convert the times in the cell its in. I want to convert it to YYWW format for a formula for a timeline in another sheet. So I use help cells with the converted value and reference those instead of the values in the other sheet.
I have done this with nested if functions resulting in mile long formulas because the timeline needs to be very long and the time can very well be 2025-Q3.
a =IF('Gulpilspuls NT'!U4="2016-Q1";1608;IF('Gulpilspuls NT'!U4="2016-Q2";1620;IF('Gulpilspuls NT'!U4="2016-Q3";1633;IF('Gulpilspuls NT'!U4="2016-Q4";1646;IF('Gulpilspuls NT'!U4="2017-Q1";1708;IF('Gulpilspuls NT'!U4="2017-Q2";1720;IF('Gulpilspuls NT'!U4="2017-Q3";1733;IF('Gulpilspuls NT'!U4="2017-Q4";1746;IF('Gulpilspuls NT'!U4="2018-Q1";1808;IF('Gulpilspuls NT'!U4="2018-Q2";1820;IF('Gulpilspuls NT'!U4="2018-Q3";1833;IF('Gulpilspuls NT'!U4="2018-Q4";1846;IF('Gulpilspuls NT'!U4="2019-Q1";1908;IF('Gulpilspuls NT'!U4="2019-Q2";1920;IF('Gulpilspuls NT'!U4="2019-Q3";1933;IF('Gulpilspuls NT'!U4="2019-Q4";1946;IF('Gulpilspuls NT'!U4="2020-Q1";2008;IF('Gulpilspuls NT'!U4="2020-Q2";2020;IF('Gulpilspuls NT'!U4="2020-Q3";2033;IF('Gulpilspuls NT'!U4="2020-Q4";2046;IF('Gulpilspuls NT'!U4="2021-Q1";2108;IF('Gulpilspuls NT'!U4="2021-Q2";2120;IF('Gulpilspuls NT'!U4="2021-Q3";2133;IF('Gulpilspuls NT'!U4="2021-Q4";2146;IF('Gulpilspuls NT'!U4="2022-Q1";2208;IF('Gulpilspuls NT'!U4="2022-Q2";2220;IF('Gulpilspuls NT'!U4="2022-Q3";2233;IF('Gulpilspuls NT'!U4="2022-Q4";2246;IF('Gulpilspuls NT'!U4="2023-Q1";2308;IF('Gulpilspuls NT'!U4="2023-Q2";2320;IF('Gulpilspuls NT'!U4="2023-Q3";2333;IF('Gulpilspuls NT'!U4="2023-Q4";2346;IF('Gulpilspuls NT'!U4="2024-Q1";2408;IF('Gulpilspuls NT'!U4="2024-Q2";2420;IF('Gulpilspuls NT'!U4="2024-Q3";2433;IF('Gulpilspuls NT'!U4="2024-Q4";2446;IF('Gulpilspuls NT'!U4="2025-Q1";2508;IF('Gulpilspuls NT'!U4="2025-Q2";2520;IF('Gulpilspuls NT'!U4="2025-Q3";2533;IF('Gulpilspuls NT'!U4="2025-Q4";2546;IF('Gulpilspuls NT'!U4="2026-Q1";2608;IF('Gulpilspuls NT'!U4="2026-Q2";2620;IF('Gulpilspuls NT'!U4="2026-Q3";2633;IF('Gulpilspuls NT'!U4="2026-Q4";2646;IF('Gulpilspuls NT'!U4="2027-Q1";2708;IF('Gulpilspuls NT'!U4="2027-Q2";2720;IF('Gulpilspuls NT'!U4="2027-Q3";2733;IF('Gulpilspuls NT'!U4="2027-Q4";2746;IF('Gulpilspuls NT'!U4="2028-Q1";2808;IF('Gulpilspuls NT'!U4="2028-Q2";2820;IF('Gulpilspuls NT'!U4="2028-Q3";2833;IF('Gulpilspuls NT'!U4="2028-Q4";2846;IF('Gulpilspuls NT'!U4="2029-Q1";2908;IF('Gulpilspuls NT'!U4="2029-Q2";2920;IF('Gulpilspuls NT'!U4="2029-Q3";2933;IF('Gulpilspuls NT'!U4="2029-Q4";2946;IF('Gulpilspuls NT'!U4="2030-Q1";3008;IF('Gulpilspuls NT'!U4="2030-Q2";3020;IF('Gulpilspuls NT'!U4="2030-Q3";3033;IF('Gulpilspuls NT'!U4="2030-Q4";3046;IF('Gulpilspuls NT'!U4="2031-Q1";3108;IF('Gulpilspuls NT'!U4="2031-Q2";3120;IF('Gulpilspuls NT'!U4="2031-Q3";3146;IF('Gulpilspuls NT'!U4="2031-Q4";3146;IF('Gulpilspuls NT'!U4="2032-Q1";3208;IF('Gulpilspuls NT'!U4="2032-Q2";3220;IF('Gulpilspuls NT'!U4="2032-Q3";3233;IF('Gulpilspuls NT'!U4="2032-Q4";3246;IF('Gulpilspuls NT'!U4="2033-Q1";3308;IF('Gulpilspuls NT'!U4="2033-Q2";3320;IF('Gulpilspuls NT'!U4="2033-Q3";3333;IF('Gulpilspuls NT'!U4="2033-Q4";3346;IF('Gulpilspuls NT'!U4="2034-Q1";3408;IF('Gulpilspuls NT'!U4="2034-Q2";3420;IF('Gulpilspuls NT'!U4="2034-Q3";3433;IF('Gulpilspuls NT'!U4="2034-Q4";3446;IF('Gulpilspuls NT'!U4="2035-Q1";3508;IF('Gulpilspuls NT'!U4="2035-Q2";3520;IF('Gulpilspuls NT'!U4="2035-Q3";3533;IF('Gulpilspuls NT'!U4="2035-Q4";3546;IF('Gulpilspuls NT'!U4="2036-Q1";3608;IF('Gulpilspuls NT'!U4="2036-Q2";3620;IF('Gulpilspuls NT'!U4="2036-Q3";3633;IF('Gulpilspuls NT'!U4="2036-Q4";3646;IF('Gulpilspuls NT'!U4="2037-Q1";3708;IF('Gulpilspuls NT'!U4="2037-Q2";3720;IF('Gulpilspuls NT'!U4="2037-Q3";3733;IF('Gulpilspuls NT'!U4="2037-Q4";3746;IF('Gulpilspuls NT'!U4="2038-Q1";3808;IF('Gulpilspuls NT'!U4="2038-Q2";3820;IF('Gulpilspuls NT'!U4="2038-Q3";3833;IF('Gulpilspuls NT'!U4="2038-Q4";3846;'Gulpilspuls NT'!U4))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
As you can clearly see this method is not the best. I cant make it this long because nested if functions can only contain 64 levels of nesting. Do you guys have a better suggestion for this?
The formula has to work with both formats of time entry and I need it to be able to convert all the cells 1:1 meaning 1 cell in the calendar has to be 1 converted cell in the other spot that I can use for the formula. If the cell in the calendar does not have YYYY-Q1234? it should just show what it is instead as you can see at the end of my formula.
Here is your formula.
=IF(AND(LEN(C6)=4,ISERROR(FIND("-",C6))),C6,MID(C6,3,2)&INDEX({"08",20,33,46},RIGHT(C6,1)))
Make sure there is no excess space in your data. Not like this "2016-Q1 ", but like this "2016-Q1".
EDIT: I just realized that if the original is in the format of YYWW, that you do NOT want it changed to the mid quarter week number. So we simplify the formulas:
=IF(ISNUMBER(-A1),A1,MID(A1,3,2) & CHOOSE(RIGHT(A1,1),"08",20,33,46))
and if you want YYWW to always be rendered as numeric:
=1*IF(ISNUMBER(-A1),A1,MID(A1,3,2) & CHOOSE(RIGHT(A1,1),"08",20,33,46))
And here are the results for various samples:
EDIT: If you need to check for blanks, you can do this simply:
=IF(LEN(A1)=0,"",1*IF(ISNUMBER(-A1),A1,MID(A1,3,2) & CHOOSE(RIGHT(A1,1),"08",20,33,46)))
However, if a 0 will not result in a downstream problem, you can use the original, shorter formula, and merely use a custom format to suppress zero returns: 0;;
And if you need to check for other conditions for which you don't want to process, you can perform similar actions.
something like this should do it, however, mid way through Q1, is week 6, so you'll need to adjust if your year doesn't start at 1/1
Function get_week(strInput As String) As String
Dim strQ As String
Dim bytQ As Byte
Dim dblMultiplier As Double
Dim intWeekNumber As Integer
strQ = Split(strInput, "-")(0)
bytQ = CByte(Right(strQ, 1))
dblMultiplier = (bytQ - 1) / 4
intWeekNumber = (dblMultiplier * 52)
intWeekNumber = intWeekNumber + (13 / 2)
get_week = Split(strInput, "-")(1) & "-" & CStr(intWeekNumber)
End Function
Let me try again
="20"&LEFT(N5,2)&IF(MOD(N5,100)<=8,"-Q1",IF(MOD(N5,100)<=20,"-Q2",IF(MOD(N5,100)<=33,"-Q3",if(MOD(N5,100)<=46,"-Q4","-Q1"))))
Should work for everything past year 2000 ;)

How to pass a date as an argument in an Excel VBA function

I'm trying to make a function that will take a date in a cell as an argument, then use that date to lookup a value. The date to be passed will be in the variable EffDate. Then the function should go to the worksheet RateChgs, check the NewPymtEffDateRange for the EffDate, and, upon finding it, go to the EscrowPymtAmtRange (one column wide) and return the value on the same row there.
I've only gotten to the point of testing it in the immediate window by typing GetEscrowPymt(8/1/2000) (or some other date). From the value of the Position variable, I can tell that the function isn't finding the date even though it's there. Is this a problem with how I'm passing the date?
Function GetEscrowPymt(EffDate As Date)
Dim PymtEffDateRange As Range
Dim EscrowPymtAmtRange As Range
Dim Position As Integer
Set PymtEffDateRange = Worksheets("RateChgs").Range("NewPymtEffDate")
Set EscrowPymtAmtRange = Worksheets("RateChgs").Range("EscrowPymt")
Position = Application.WorksheetFunction.Match(EffDate, PymtEffDateRange, 1)
MsgBox (Position)
End Function
The last argument in the Match function allows for returning an approximate match. If you require an exact match, then you should use the last argument of 0 to require an exact match. Otherwise, using the arguments 1 or -1 will return approximate match and assume also that the data is sorted ascending.
Position = Application.WorksheetFunction.Match(EffDate, PymtEffDateRange, 0)
The Match function will error if the effDate value is not found in the lookup array, so you may need error handling logic to account for that possibility. I would probably use the Application.Match function which can accept an error type, where the Match function in the Worksheet class will only accept long/integer values and will raise an error if the value isn't found:
Dim Position as Variant
Position = Application.Match(EffDate, PymtEffDateRange, 0)
If IsError(Position) Then
MsgBox EffDate & " not found!", vbInformation
Exit Function
' -- OR --
' assign some other return value for the function, etc.
End If
Some functions also have difficulty working with date values, so let me know if that doesn't solve the issue.
VBA also doesn't play well with various system locales, if you're expecting "8/1/2000" to be anything other than August 1, 2000, you may have more problems since VBA will interpret that by the US date format, not the system locale (e.g., in the UK that date would be 8 January, 2000). In that case, it may be best to treat the date as text and do a match based on text rather than date.

Excel VBA creating a new column with formula

I have an excel file with a column which has date data. I want the user to input a date of their choosing and then I want to create a new column that lists the difference in days between the two dates. The Macro that I have is working but I have a few questions and I would like to make it better. Link to MWE small data file is here.
The user input date was 9/30/2013, which I stored in H20
Macro:
Sub Date_play()
Dim x As Date
Dim x2 As Date
Dim y As Variant
x = InputBox(Prompt:="Please enter the Folder Report Date. The following formats are acceptable: 4 1 2013 or April 1 2013 or 4/1/2013")
x2 = Range("E2")
y = DateDiff("D", x2, x)
MsgBox y
'Used DateDiff above and it works but I don't know how to use it to fill a column or indeed a cell.
Range("H20").FormulaR1C1 = x
Range("H1").FormulaR1C1 = "Diff"
Range("H2").Formula = "=DATEDIF(E2,$H$20,""D"")"
Range("H2").AutoFill Destination:=Range("H2:H17")
Range("H2:H17").Select
End Sub
Now, could I have done this without storing the user input date in a particular cell? I would've preferred to use the variable "x" in the formula but it wasn't working for me. I had to store the user input in H20 and then use $H$20.
What's the difference between the function Datedif and the procedure DateDiff? I am able to use the procedure DateDiff in my macro but I don't know how to use it to fill out my column. Is one method better than the other?
Is there a better way to add columns to the existing sheet, where the columns include some calculations involving existing data on the sheet and some user inputs? There are tons of more complicated calculations I want to do next.
Thanks
Q1. Now, could I have done this without storing the user input date in a particular cell? I would've preferred to use the variable "x" in the formula but it wasn't working for me. I had to store the user input in H20 and then use $H$20.
Try this (UNTESTED)
Replace
Range("H20").FormulaR1C1 = x
Range("H1").FormulaR1C1 = "Diff"
Range("H2").Formula = "=DATEDIF(E2,$H$20,""D"")"
Range("H2").AutoFill Destination:=Range("H2:H17")
Range("H2:H17").Select
by
Range("H2:H17").Formula = "=DATEDIF(E2," & datevalue(x) & ",""D"")"
The above will fill all the cells with the formula in one go. You do not need the Autofill to do the job. Also Inputbox is the worst choice to accept dates. You might want to see THIS
Q2. What's the difference between the function Datedif and the procedure DateDiff? I am able to use the procedure DateDiff in my macro but I don't know how to use it to fill out my column. Is one method better than the other?
DATEDIF is a worksheet function and DateDiff is a VBA Function.

vb.net - How to get the day number from a weekday name

Long story short:
I need the inverted function of WeekdayName(), in the following terms:
You provide a week day name (e.g. Sunday)
You get the correspondent week day number (that depends which is the first week day as returned in WeekdayName, e.g., you get 1 for Sunday if Sunday is the first day of the week)
Background:
I'm using date functions in vb.net. So far so good. I'm using the function WeekdayName() in order to set the titles for tab pages in a TabControl. My custom control (kind of calendar control) holds the mentioned TabControl and it has the option of choosing which day of the week you want to diplay.
If you want to display ALL days, the TabControl will have TabPages filled by iterating upon the WeekdayName() function mentioned above (localized and managed by the system calendar and capitalized by me).
If you set only Tuesday and Friday, you will have two tab pages with those titles and sorted as [Tuesday | Friday]. If you decide to add Wednesday, now you should have 3 tab pages: [Tuesday | Wednesday | Friday], and so on...
In order to keep tabs sorted, when I need to insert a tab to be shown I want to provide the tab's title to check against the new-to-insert weekday name and in that way have the order resolved.
I believe one workaround is to create a fake date object with the tab's title string in it in order to have a, for instance, "Sunday" date and then use: Weekday() but I was hoping an API solution.
NOTE: This is not: how to get the day number from a date.
EDIT:
As we disscused with #jmshapland, a custom code approach using the default localization and system settings could be:
Function WeekdayNumber(day as String)
' The following initialization does not necessary go in this function.
' The idea is to have a mapping between key day name and index in the
' same order as the WeekdayName() method with the default system settings
Dim weekdayNamesCollection as Collection = New Collection()
For i = 1 to WEEKDAYS
Dim wDay as String = WeekdayName(i)
' add the day with a key with the same name
weekdayNamesCollection.add(wDay, wDay)
Next i
If weekdayNamesCollection.ContainsKey(day) Then
Return weekdayNamesCollection.IndexOfKey(day) + 1
End If
' Raise an error as the string 'day' is not in the collection
End Sub
I didn't test this out as I am in a computer without any framework and/or IDE. But basically, the idea is to return the index where the weekday name is stored in the collection (previously, it was stored in the system settings order as WeekdayName().
I don't think there's a built-in function for it. But if you are using WeekdayName then you should use it for your purpose.
Public Function WeekDayNumber(ByVal weekName As String) As Integer
Dim weekNames As New Dictionary(Of String, Integer)
For i As Integer = 1 To 7
weekNames.Add(WeekdayName(i), i)
Next
Return weekNames(weekName)
End Function
Sorry if this is formatted poorly, I never work with VB usually just C#. However, this should do what you are looking for... If you want the first day of the week to return as 0 instead of 1 just remove the + 1 from the return statement.
Private Function FindDayOfWeek(day As String) As Integer
Dim daysOfWeek = CultureInfo.CurrentCulture.DateTimeFormat.DayNames
Dim counter As Integer = Array.IndexOf(daysOfWeek, WeekdayName(1))
Dim numericDay As Integer
For i As Integer = 0 To 6
If counter > 6 Then
counter = 0
End If
If daysOfWeek(counter) = day Then
numericDay = i
Exit For
End If
counter += 1
Next
Return numericDay + 1
End Function
By using val() function, will give Day of Week number from 0 to 6 :
intDayofWeek = val(System.DateTime.Now.DayOfWeek)

Excel VBA: How do you format Charts in Excel with New Data?

I'm trying to make a macro that formats a chart in Excel 2003 where the data changes. Basically, I have a 20 X values and Y values at all times; however, the values are data specific (I'm making stock price charts that will change depending on the stock I'm analying). I'm trying to make my Y-Axis cross the X axis at the value in cell B8; is there anyway to do this with a macro? Because I can't link where the axes cross to a cell. Also, I want to change the axis minimum to cell B8 as well. Also I want the macro to adjust the cart to look logical automatically depending on the data I put in there (ie logical intervals).
The chart type here is a Scatter plot, where the desription is: "Scatter with Data Points Connected by Lines Without Markers". Thank you very much.
I don't think it's possible to dynamically link the intercept value to a cell - this is just based on the fact that the UI for selecting the intercept value requires an explicit value, rather than allowing you to select a cell.
Within VBA, however, once you have read the desired value from the cell, do
ActiveSheet.ChartObjects("Chart 1").Axes(xlValue).CrossesAt = value
(with your chart name)
This is approximately what you need (no time here to test and get the details exact):
ActiveChart.Axes(xlValue).CrossesAt = Range("B8").value
You might also have to set
ActiveChart.Axes(xlCategory).Crosses = xlAxisCrossesCustom
and play around a little with whether to use Value or Category.
"to adjust the cart to look logical automatically depending on the data I put in there (ie logical intervals)."
That one is a lot of fun. Here's a VBA function that does the hard part of calculating a pretty interval between the ticks.
Public Function prettyVal( _
xMin As Double, _
xMax As Double, _
minBins As Integer) _
As Double
'' returns an aesthetic interval size to _
use for a plot axis or histogram bin. _
marc#smpro.ca 2010-09-01
Dim pretties
pretties = Array(1, 2, 5, 10)
Dim maxBin As Double ''maximum size of bin
Dim xScale As Double ''scale factor
With WorksheetFunction
maxBin = (xMax - xMin) / minBins
xScale = 10 ^ Int(.Log10(maxBin))
prettyVal = xScale * .Lookup(maxBin / xScale, pretties)
End With
End Function
You'll want to use it in a worksheet. Use the floor and ceiling of the min and max with the pretty value for significance. This makes them also pretty. Something like this in the worksheet:
minimum plot value minVal 120
maximum plot value maxVal 980
minimum num of bins minBins 10
pretty bin size binsize 50 =prettyVal(minVal,maxVal,minBins)
low axis value minEdge 100 =FLOOR(minVal,binsize)
high axis value maxEdge 1000 =CEILING(maxVal,binsize)
number of bins numBins 18 =(maxEdge-minEdge)/binsize
Enjoy.