从 Zoomable Graph C# 计算

Calculation from Zoomable Graph C#

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

所以我在另一个选项卡上的富文本框中放置了一些最小值、最大值和平均值。如下代码所示:

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

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

如果您不明白我的意思,请给我留言,我会提供更多信息。

要在 缩放滚动 后更新基于可见 Points 的统计计算,您需要知道两件事:什么时候你应该这样做,哪些点是可见的。

要使用的事件是AxisViewChanged,很简单。连接后,您可以调用一个函数来更新您的统计信息:

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

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

乍一看,您可能认为 ViewEventArgs 参数有帮助;毕竟它有这样有前途的数据:NewPositionNewSize

但仔细观察你会发现两者都是双打,所以除非你的 XValues 已设置为从 0 到 1 计数,否则它们不会索引到 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;
}