1

I have a horizontally stacked bar chart in my app, and I'm trying to figure out how to get the X axis value when the user clicks on a bar. The problem is when I look at the values at runtime, the Y values are fine but the X values are all 0.

Screen capture

In the image above, light blue bars are from Series[0] and represent the MTD sales and the darker ones from Series[1] represent last year's sales for the same month. My goal is that when the user double-clicks on a bar, he is taken to the detailed sales report for that salesperson.

I haven't tried switching my chart to a regular bar chart because this is what I will need to look like in the end. But I'm starting to wonder if the reason I'm getting all 0's in the XValue field is because of this or because I am using strings as the type of value.

Has anyone ever encountered this or have any clues as to how to fix it?

Screen capture of points at runtime

Klev330
  • 11
  • 4

2 Answers2

1

You use one of the Bar chart types.

They have their x-axis and y-axis switched compared to most normal types.

Therefore in order to get the values along the horizontal axis you actually want to grab the y-values.

To get at the y-value of the double-clicked datapoint you can do a HitTest like in this code:

private void chart1_MouseDoubleClick(object sender, MouseEventArgs e)
{
    var hit = chart1.HitTest(e.X, e.Y, ChartElementType.DataPoint);
    if (hit.PointIndex >= 0)
    {
        DataPoint dp = hit.Series.Points[hit.PointIndex];
        Console.WriteLine(dp.YValues[0]);
    }
}

Note however that in a stacked bar the values look stacked but each point will still only have its own value.

If you wanted to get at the stacked/summed up values you would have to add up all points below and including the one that was hit. 'Below' here means points at the same x-slot but in lower series!

You will not be able to use the x-values if you have added them as strings since in that case they will all be 0, as you can see in your screenshot.

But since all stacked points in your case will have the same e.PointIndex we can use this to access all points in the series below..:

    ..
    int si = 0;
    double vsum = 0;
    Series s = null;
    do
    {
        s = chart4.Series[si++];
        vsum += s.Points[hit.PointIndex].YValues[0];

    } while (hit.Series != s);
    Console.WriteLine(vsum);

If you actually want to access the x-values you have two options:

  • You can explicitly add the strings to the AxisLabel of each DataPoint. While the x-values will still be all 0 the AxisLabels now can be accessed.

  • Or you can add them as numbers, maybe using some scheme to map the strings to numbers and back and, again set the AxisLabels.

TaW
  • 53,122
  • 8
  • 69
  • 111
  • That makes a lot of sense. From what your saying, I will never be able to get the vertical value (xValue) in this situation because my chart has strings as the xValue type. Is there a workaround? Maybe I could use the employeeID as the xValue (type int16), but could I still somehow replace the labels on that axis so it's user friendly? – Klev330 Oct 30 '18 at 01:55
  • Yes, that is right. Add the x-values as numbers (internally all values are double) and set the AxisLabel of each DataPoint individually to whatever text you want. you could choose points.count or some other scheme. Note that they should be ordered and the same over the series to keep the stacking corrcet!! Only point with the same x-value get stacked, or for normal bars grouped. – TaW Oct 30 '18 at 07:50
  • You may want to have a look at [this post](https://stackoverflow.com/questions/31478763/is-it-possible-to-match-two-series-of-data-in-a-chart-from-two-different-dataset/31483413?s=1|42.0111#31483413) for more details. (My post, not the accepted answer!) – TaW Oct 30 '18 at 08:01
0

OK so I finally managed to put custom labels on the chart using the Chart.Customize event.

Here is the data I am using for this chart:

Vendeur     |   Total    |    idDepartement   |   idEmploye   | TotalLastYear
Ghislain        5256.30       1                   56                0.00
Kim            12568.42       1                    1            74719.18
Philippe       17565.27       1                   44            38454.85

I changed X axis XValueType to Double, and the XValueMember to idEmploye.

Result

As you can see, it's not very user friendly to have employee id's on a chart. This is where the Customize event gets useful.

Here is my event:

private void chart1_Customize(object sender, EventArgs e)
    {
        // Set X axis interval to 1, label will be centered (between 0.5 and 1.5)
        chart1.ChartAreas[0].AxisX.Interval = 1;
        double startOffset = 0.5;
        double endOffset = 1.5;

        chart1.ChartAreas[0].AxisX.CustomLabels.Clear();

        // Cycle through chart Datapoints in first serie
        foreach (System.Windows.Forms.DataVisualization.Charting.DataPoint pt in chart1.Series[0].Points)
        {

            // First get the dataset used for the chart (from its bindingsource)
            DataSet dsSales = (DataSet)bsViewVentesParUtilisateurSignsMoisCourant.DataSource;

            // Second get the datatable from that dataset based on the datamember 
            // property of the bindingsource
            DataTable dtSales = (DataTable)dsSales.Tables[bsViewVentesParUtilisateurSignsMoisCourant.DataMember];

            // Get a dataview and filter its result based on the current point's XValue
            DataView dv = new DataView(dtSales);
            dv.RowFilter = "idEmploye=" + pt.XValue.ToString();

            // Get the "Salesperson" (or "Vendeur") column value from the first result
            // (other rows will have the same value but row 0 is safe)
            string firstname = dv.ToTable().Rows[0].Field<string>("Vendeur").ToString();

            // Create new customlabel and add it to the X axis
            CustomLabel salespersonLabel = new CustomLabel(startOffset, endOffset, firstname, 0, LabelMarkStyle.None);
            chart1.ChartAreas[0].AxisX.CustomLabels.Add(salespersonLabel);
            startOffset += 1;
            endOffset += 1;
        }
    }

Final result

I am very happy with the result. And now when I double-click on a bar in the chart, I can get the employee id from the X value and generate the code to get the detailed sales report for that person for the given month.

Klev330
  • 11
  • 4