Chart: Show more value descriptions on X-Axis

2020-03-09 11:45发布

问题:

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

回答1:

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:

  1. For your reference
  2. 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


回答2:

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