从 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
参数有帮助;毕竟它有这样有前途的数据:NewPosition
和 NewSize
。
但仔细观察你会发现两者都是双打,所以除非你的 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;
}
基本上我有一个从 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
参数有帮助;毕竟它有这样有前途的数据:NewPosition
和 NewSize
。
但仔细观察你会发现两者都是双打,所以除非你的 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;
}