从Zoomable Graph C#计算

时间:2015-05-09 15:41:05

标签: c# graph datagridview charts axis

基本上我有一个从DataTable绑定的图表,该源图来自DataGridView。我在图表上有可缩放的函数,我需要使用X Axis SelectionStart和SelectionEnd来计算所选的数据块。

所以我在另一个标签页上的richtextbox中放置了一些最小值和平均值。如下面的代码所示:

//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");

现在在下面的图片中,您可以看到图表的图像及其显示的数据,以下是将数据表绑定到图表的代码。

 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);
        }

现在我需要做的是在Graph附近有另一个文本框,每次我缩放并且灰色块出来时它会显示我选择的块的最小值maximiums和averages!然后当我缩小时,它会重置为原始。

如果你不明白我的意思,请给我留言,我会提供更多信息。 enter image description here

1 个答案:

答案 0 :(得分:1)

要在缩放滚动之后根据可见Points更新统计计算,您需要了解两件事:何时应该你这样做,哪些点是可见的。

要使用的事件是AxisViewChanged,这很容易。连接完毕后,您可以调用函数来更新统计信息:

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

困难的部分是知道Points集合的哪一部分可见。

乍一看,您可能会认为ViewEventArgs parm有帮助;毕竟它有如下有希望的数据:NewPositionNewSize

但仔细观察,你会发现两者都是双打的,所以除非你的XValues已经从0开始计数,否则他们不会将Points集合编入索引。

相反,我们必须对这些值进行一些搜索,从左侧为最小值,右侧为最大值。这是一个这样做的功能:

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);
}

从这里开始,事情变得容易多了;我们可以对我们的系列做统计,也许是这样:

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!
}

使用简单的函数进行数学运算:

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;
}