6

I have aligned the annotations to data points; I want to align the annotations vertically.

I have read this, But can't figure out how to relate the chart width to data points. https://msdn.microsoft.com/en-us/library/dd456731.aspx

And this: MS Charting Annotations refuse to align to mouse position

I added a picture of the chart so far as an example.

'create new chart
 chart1 = New DataVisualization.Charting.Chart

 'add chart areas
  chart1.ChartAreas.Add("NewChartArea")
  chart1.ChartAreas("NewChartArea").Area3DStyle.Enable3D = False
  chart1.ChartAreas("NewChartArea").AxisX.MajorGrid.Enabled = False 'turn chart background grid on and off
  chart1.ChartAreas("NewChartArea").AxisY.MajorGrid.Enabled = False 'turn chart background grid on and off
  chart1.ChartAreas("NewChartArea").AxisX.Title = "Activities of daily living" '----> title on the bottom for the x axis
  '[template] chart1.ChartAreas("NewChartArea").AxisX.LabelStyle.Angle = 45
  '[template] Chart1.Series(SeriesZeroChartName).Label = " my own label" ' -----> adds a label at the top of each bar

   For c As Integer = 2 To Me.DataGridViewResultsAdls.ColumnCount - 1

        Dim NextSeriesChartName As String
        NextSeriesChartName = DataGridViewResultsAdls.Columns(c).Name

        chart1.Series.Add(NextSeriesChartName)
        chart1.Series(NextSeriesChartName).ChartType = DataVisualization.Charting.SeriesChartType.Bar 'CHART CHANGER ******  change this value to change chart type
        chart1.Series(NextSeriesChartName).Points.Clear()
        chart1.Series(NextSeriesChartName).IsValueShownAsLabel = True '----> puts little labels ontop of each bar
        chart1.Series(NextSeriesChartName).SmartLabelStyle.Enabled = True


       ' fill each subsequent series with points
         For Count As Integer = 0 To DataGridViewResultsAdls.Rows.Count - 2
                Dim NextColumnName As String
                NextColumnName = DataGridViewResultsAdls.Columns(c).Name

                ' define X values
                Dim XLabelMyCustom As String
                XLabelMyCustom = DataGridViewResultsAdls.Item(0, Count).Value
                'define Y values
                Dim YLabelMyCustom As String
                YLabelMyCustom = DataGridViewResultsAdls.Item(NextColumnName, Count).Value

                ' add the point to the chart
                chart1.Series(NextSeriesChartName).Points.AddXY(XLabelMyCustom, YLabelMyCustom)

                ' create custom labels for the x axis
                chart1.ChartAreas("NewChartArea").AxisX.CustomLabels.Add(Count + 0.5, Count + 0.4 + 0.5, "Q2", 0, DataVisualization.Charting.LabelMarkStyle.None)
                chart1.ChartAreas("NewChartArea").AxisX.CustomLabels.Add(Count + 0.5 + 0.5, Count + 0.9 + 0.5, "Q1", 0, DataVisualization.Charting.LabelMarkStyle.None)
                chart1.ChartAreas("NewChartArea").AxisX.CustomLabels.Add(Count + 0.5, Count + 1, "Q3", 2, DataVisualization.Charting.LabelMarkStyle.LineSideMark)



                'Create a variable MyDataPoint to hold the current datapoint
                Dim MyDataPoint As DataPoint
                MyDataPoint = chart1.Series(NextSeriesChartName).Points(Count)
                'Create a new text annotation
                Dim MyTextAnnotation As TextAnnotation
                MyTextAnnotation = New TextAnnotation
                MyTextAnnotation.Text = "some notation"
                '[template] MyTextAnnotation.X =   <---- sets coordinates on screen for x
                '[template ]MyTextAnnotation.Y =   <---- sets coordinates on screen for y
                '[template] MyTextAnnotation.AnchorDataPoint = MyDataPoint  'sets the point where the notation will be
                '[template] chart1.Annotations.Add(MyTextAnnotation) ' adds the notation to the chart

                ' only add annotations to the chart once per series
                If c = 2 Then
                    MyTextAnnotation.AxisY = chart1.ChartAreas("NewChartArea").AxisY

                    ' [template] chart1.Series(NextSeriesChartName).Points.Item(Count).ToString  <--- output points to a string {x,y}


                    MyTextAnnotation.AnchorDataPoint = MyDataPoint  'sets the point where the notation will be
                    chart1.Annotations.Add(MyTextAnnotation) ' adds the notation to the chart
                    MyTextAnnotation.AnchorOffsetX = -10


                End If
            Next

        Next

        'Add chart to control and set dock to fill
        Me.PanelChartAdls.Controls.Add(chart1)
        chart1.Dock = DockStyle.Fill

    End If
Community
  • 1
  • 1
Shane Arpas
  • 63
  • 1
  • 6
  • Can you draw the positions you want into your screenshot? (Nice [Red Circles](http://meta.stackexchange.com/questions/19478/the-many-memes-of-meta), btw..) - You probably need some [Offset](https://msdn.microsoft.com/en-us/library/system.windows.forms.datavisualization.charting.annotation.anchoroffsety%28v=vs.110%29.aspx) – TaW May 04 '16 at 11:37
  • :) I did, the position where I would like the annotations is on the yellow highlight :) I tried using the off set, but am unsure how to calculate it accurately as the data points use a % representative of the chart height and width – Shane Arpas May 04 '16 at 14:54
  • Also the x axis is vertical on this chart, as it is a bar chart, so the X-axis of the plot points relates to the height of the chart - i think – Shane Arpas May 04 '16 at 15:04

1 Answers1

5

Positioning in a Chart control is rather complex.

To begin with a chart has three coordinate systems:

  • The data values
  • Percentages of some area, most notably the ChartArea and the InnerPlotPosition
  • Pixels of the Chart control's ClientArea

The simplest way to achieve an alignment of your Annotations is to first anchor each to its DataPoint:

MyTextAnnotation.AnchorDataPoint = MyDataPoint 

Next you override the X-Position to a value you like:

MyTextAnnotation.X = someValue;

A few notes:

  • While by default the Annotation.Position would use percentages, after anchoring it to a DataPoint it uses the values instead. So using 50 would not place in somewhere around the middle but all to the right...

Looking at your Chart I suggest using a value of 3.

  • If your values vary this positioning will also vary. And when you resize the Chart the Axes will be resized and the Annotations will move as well.

Btw: The percentages are in relation to the next outer container: The ChartAreas to the Chart.ClientRectangle, the InnerPlotPostion to the ChartArea and each element to the container it is docked to..

  • The Positions are by default set to automatic so their values are NaN. To access the (current) values you can call ElementPosition.ToRectangleF().

  • Also note that there are several functions on the Chart's Axes that will convert values, pixels and percent-positions.

However you need to find a valid moment to call those functions; if the Chart is not done with its layout, they will return null.

You can safely either call them in one of the three Paint events or in response to a user interaction like a Mouse event.

Here is how to use them for positioning all Annotations to a (somewhat) fixed pixel position:

private void chart1_PostPaint(object sender, ChartPaintEventArgs e)
{
    Axis AY = chart1.ChartAreas[0].AxisY;

    double pypx = AY.ValueToPosition(AY.PixelPositionToValue(30));

    foreach (TextAnnotation ta in chart1.Annotations)
    {
        ta.X = pypx;
    }
}

Now the Annotations will not move when the chart is resized or when the data values grow or shrink. At least not a lot; a few jumps can be seen. Either because I missed something or because of rounding issues.

But I suggest going with the simpler method of setting their X-Position to a fixed value on your axis..:

MyTextAnnotation.X = 3;

This would put them at the yellow line you drew.

TaW
  • 53,122
  • 8
  • 69
  • 111
  • ! Thank You So Much ! That answer is great on so many levels. I really appreciate the time taken. – Shane Arpas May 05 '16 at 07:13
  • Could you recommend resources so I may learn more about the charting process above ? – Shane Arpas May 05 '16 at 08:50
  • Not really beyond MSDN, as the Chart control is not well documented and what I know was learned by searching high and low. You may want to read through a couple of [SO posts of mine](http://stackoverflow.com/search?tab=newest&q=user%3a3152130%20ChartArea) though that deal with these issues.. (The more recent they are, the more I knew when I wrote them ;-) – TaW May 05 '16 at 09:05
  • Could i trouble you for an example of how to calculate percentages ? or a resource for that, I am quite interested in the topic – Shane Arpas May 05 '16 at 09:35
  • To get a percentage aka position from a datavalue you use the ValueToPosition fuction. To get it from pixels you need to combine it with PixelPositionToValue. Both are shown in the last piece of code. If you want to you can also get the pixelwidth of the innerplotposition and use it to calculate the percentages from a pixel size you want.. Among the linked posts [this one](http://stackoverflow.com/questions/36491231/ms-chart-rectangular-annotation-width-in-percent-and-not-pixel/36497262?s=5|0.0000#36497262) calculates percent from pixels. – TaW May 05 '16 at 09:50