1

Basically I have a graph that is bound from a DataTable which source is from a DataGridView. I have zoomable functions on the graph and I need it use X Axis SelectionStart and SelectionEnd in order to calculate the block of data that is selected.

So I have some minimums maximums and averages placed in a richtextbox on another tab. As shown below in the code:

//To show the Data from file into the TextBox                                                          
        richTextBox1.AppendText("\n" + "Heart Average : " + HRM.Active.DataRows.Average(r => r.HeartRate) + "\n");
        richTextBox1.AppendText("\n" + "Heart Minimum : " + HRM.Active.DataRows.Min(r => r.HeartRate) + "\n");
        richTextBox1.AppendText("\n" + "Heart Maximum : " + HRM.Active.DataRows.Max(r => r.HeartRate) + "\n");
        richTextBox1.AppendText("\n" + "Average Speed (KM/H): " + HRM.Active.DataRows.Average(r => r.Speed) + "\n");
        richTextBox1.AppendText("\n" + "Maximum Speed : " + HRM.Active.DataRows.Max(r => r.Speed) + "\n");
        richTextBox1.AppendText(Environment.NewLine + " - (MPH): " + "");
        richTextBox1.AppendText("\n" + "Average Power: " + HRM.Active.DataRows.Average(r => r.Power) + "\n");
        richTextBox1.AppendText("\n" + "Maximum Power : " + HRM.Active.DataRows.Max(r => r.Power) + "\n");
        richTextBox1.AppendText("\n" + "Average Altitude (KM/H): " + HRM.Active.DataRows.Average(r => r.Altitude) + "\n");
        richTextBox1.AppendText("\n" + "Maximum Altitude : " + HRM.Active.DataRows.Max(r => r.Altitude) + "\n");
        richTextBox1.AppendText("\n" + "Cadence Average : " + HRM.Active.DataRows.Average(r => r.Cadence) + "\n");
        richTextBox1.AppendText("\n" + "Cadence Maximum : " + HRM.Active.DataRows.Max(r => r.Cadence) + "\n");
        richTextBox1.AppendText("\n" + "Pressure Average : " + HRM.Active.DataRows.Average(r => r.Pressure) + "\n");
        richTextBox1.AppendText("\n" + "Pressure Maximum : " + HRM.Active.DataRows.Max(r => r.Pressure) + "\n");

Now in the image below you can see the image of the Graph and the data it shows on there, Here is the code which binds the datatable to the graph.

 protected void drawChart()
    {
        DataTable dt = new DataTable();
        dt.Clear();
        foreach (DataGridViewColumn col in dataGridView1.Columns)
        {
            dt.Columns.Add(col.HeaderText);
        }
        foreach (DataGridViewRow row in dataGridView1.Rows)
        {
            DataRow dRow = dt.NewRow();
            foreach (DataGridViewCell cell in row.Cells)
            {
                dRow[cell.ColumnIndex] = cell.Value;
            }
            dt.Rows.Add(dRow);
        }

Now what I need to do is have another textbox near the Graph and every time I zoom and the grey block comes out it displays the minimums maximiums and averages for the block i have selected! Then when I zoom out it resets to the original.

If you do not understand what I mean just message me and I will give more information. enter image description here

mvoase
  • 544
  • 1
  • 6
  • 20
  • Do have a llok at [this post](http://stackoverflow.com/questions/30055627/mschart-select-a-portion-of-data-and-update-chart/30061259#30061259). Here a very similar problem is solved. At least how to calculate something like an average from the selected/visible points. - Displaying them inside the Chart is another matter; you could add a custom legend to display live statistics.. – TaW May 09 '15 at 17:31
  • Is there any other way I could contact you except on here for some more help?.. Just faster as I do not have chat functions yet. – mvoase May 09 '15 at 17:34
  • You can go to chat (now) by picking chat in the stackExchnge dropdown at the top left, or by re-entering [the old room](http://chat.stackoverflow.com/rooms/77095/discussion-on-answer-by-taw-chart-zoom-in-to-show-more-precise-data) – TaW May 09 '15 at 17:49

1 Answers1

1

To update a statistical calculation based on the visible Points after zooming or scrolling you need know two things: When should you do it and which points are visible.

The event to use is AxisViewChanged, that's easy. After you have hooked it up you can call a function to update your statistics:

private void chart1_AxisViewChanged(object sender, ViewEventArgs e)
{
    updateStats();
}

The difficult part is to know which portion of the Points collection is visible.

At first glance you may think that the ViewEventArgs parm helps; after all it has such promising data as: NewPosition and NewSize.

But looking closer you will see that both are doubles, so unless your XValues have been set counting up from 0 by 1, they won't index into the Points collection.

Instead we must do a little searching for those values, from left for the minimum and from the right for the maximum. Here is a function to do so:

int getVisiblePoint(Chart chart, Series series, bool first)
{
    Series S = series;
    ChartArea CA = chart.ChartAreas[S.ChartArea];
    DataPoint pt = null;
    if (first)  pt = S.Points.Select(x => x)
                                .Where(x => x.XValue >= CA.AxisX.ScaleView.ViewMinimum)
                                .DefaultIfEmpty(S.Points.First()).First();
    else    pt = S.Points.Select(x => x)
                        .Where(x => x.XValue <= CA.AxisX.ScaleView.ViewMaximum)
                        .DefaultIfEmpty(S.Points.Last()).Last();

    return S.Points.IndexOf(pt);
}

From here on things get a lot easier; we can do statistics on our series, maybe like this:

void updateStats()
{
    int firstPt = getVisiblePoint(chart1, chart1.Series[0], true);
    int lastPt = getVisiblePoint(chart1, chart1.Series[0], false);
    int sCount = chart1.Series.Count;
    double[] avg = new double[sCount];
    double[] min = new double[sCount];
    double[] max = new double[sCount];

    for (int i = 0; i < sCount; i++)
    {
        Series S = chart1.Series[i];
        avg[i] = getAverage(S, firstPt, lastPt);
        min[i] = getMixMax(S, firstPt, lastPt, true);
        max[i] = getMixMax(S, firstPt, lastPt, false);
    }
    // insert code to display the data here!
}

using simple functions to do the math:

double getAverage(Series series, int first, int last)
{
    double sum = 0;
    for (int i = first; i < last; i++) sum += series.Points[i].YValues[0];
    return sum / (last - first + 1);
}

double getMixMax(Series series, int first, int last, bool min)
{
    double val = 0;

    for (int i = first; i < last; i++)
    {
        double v = series.Points[i].YValues[0];
        if ( (min && val > v) || (!min && val >= v)) val = v;
    }
    return val;
}
TaW
  • 53,122
  • 8
  • 69
  • 111