Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi TeeChart通过给定的X值获取序列Y值或索引_Delphi_Teechart - Fatal编程技术网

Delphi TeeChart通过给定的X值获取序列Y值或索引

Delphi TeeChart通过给定的X值获取序列Y值或索引,delphi,teechart,Delphi,Teechart,我有以下问题:我正在使用Delphi XE3和TeeChart,我想通过给定的X值检索Y值或序列的值索引。我的意甲是一个时间序列,日期在X轴上。我知道图表上的日期,我想显示与此日期最近的对应Y值 TChart或TChartSeries组件是否有任何方法或功能来实现这一点?或者,我需要迭代该系列,直到到达所选日期 不可能使用cursorposition方法,因为光标可能位于任何位置 提前感谢您的帮助。您可以使用TChartValueList的Locate方法获取适当数据输入的索引 帮助中的示例:

我有以下问题:我正在使用Delphi XE3和TeeChart,我想通过给定的X值检索Y值或序列的值索引。我的意甲是一个时间序列,日期在X轴上。我知道图表上的日期,我想显示与此日期最近的对应Y值

TChart或TChartSeries组件是否有任何方法或功能来实现这一点?或者,我需要迭代该系列,直到到达所选日期

不可能使用cursorposition方法,因为光标可能位于任何位置


提前感谢您的帮助。

您可以使用
TChartValueList
Locate
方法获取适当数据输入的索引

帮助中的示例:

tmp:=LineSeries1.XValues.Locate(EncodeDate(2007,1,1));
if tmp<>-1 then ...

解决方案是插值算法,如所有功能\欢迎\中的图表样式\标准\线(条带)\插值线示例。下面是该示例的完整代码:

unit Line_Interpolate;
{$I TeeDefs.inc}

interface

uses
  {$IFNDEF LINUX}
  Windows, Messages,
  {$ENDIF}
  SysUtils, Classes,
  {$IFDEF CLX}
  QGraphics, QControls, QForms, QDialogs, QExtCtrls, QStdCtrls, QComCtrls,
  {$ELSE}
  Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, ComCtrls,
  {$ENDIF}
  Base, TeEngine, Series, TeeProcs, Chart, TeeTools, TeeGDIPlus;

type
  TLineInterpolateForm = class(TBaseForm)
    Series1: TLineSeries;
    CheckBox1: TCheckBox;
    Series2: TLineSeries;
    Series3: TLineSeries;
    ChartTool1: TCursorTool;
    ChartTool2: TGridBandTool;
    procedure FormCreate(Sender: TObject);
    procedure Chart1AfterDraw(Sender: TObject);
    procedure ChartTool1Change(Sender: TCursorTool; x, y: Integer;
      const XValue, YValue: Double; Series: TChartSeries;
      ValueIndex: Integer);
  private
    { Private declarations }
    xval: Double;
    function InterpolateLineSeries(Series: TChartSeries;XValue: Double): Double; overload;
    function InterpolateLineSeries(Series: TChartSeries; FirstIndex,
                                  LastIndex: Integer; XValue: Double): Double; overload;
  public
    { Public declarations }
  end;

implementation

{$IFNDEF CLX}
{$R *.DFM}
{$ELSE}
{$R *.xfm}
{$ENDIF}

procedure TLineInterpolateForm.FormCreate(Sender: TObject);
var i: Integer;
begin
  inherited;

  for i:=0 to Chart1.SeriesCount-1 do
    Chart1[i].FillSampleValues;
end;

function TLineInterpolateForm.InterpolateLineSeries(Series: TChartSeries;
  XValue: Double): Double;
begin
  result:=InterpolateLineSeries(Series,Series.FirstDisplayedIndex,Series.LastValueIndex,XValue);
end;

function TLineInterpolateForm.InterpolateLineSeries(Series: TChartSeries;
  FirstIndex, LastIndex: Integer; XValue: Double): Double;
var
  Index: Integer;
  dx,dy: Double;
begin
  for Index:=FirstIndex to LastIndex do
    if Series.XValues.Value[Index]>XValue then break;

  //safeguard
  if (Index<1) then Index:=1
  else if (Index>=Series.Count) then Index:=Series.Count-1;

  // y=(y2-y1)/(x2-x1)*(x-x1)+y1
  dx:=Series.XValues.Value[Index] - Series.XValues.Value[Index-1];
  dy:=Series.YValues.Value[Index] - Series.YValues.Value[Index-1];

  if (dx<>0) then
    result:=dy*(XValue - Series.XValues.Value[Index-1])/dx + Series.YValues.Value[Index-1]
  else result:=0;
end;

procedure TLineInterpolateForm.Chart1AfterDraw(Sender: TObject);
var xs, ys, i: Integer;
begin
  if CheckBox1.Checked then
  begin
    xs := Chart1.Axes.Bottom.CalcXPosValue(xval);

    for i:=0 to Chart1.SeriesCount - 1 do
    begin
      ys := Chart1[i].GetVertAxis.CalcYPosValue(InterpolateLineSeries(Chart1[i],xval));
      Chart1.Canvas.Brush.Color := Chart1[i].Color;
      Chart1.Canvas.Ellipse(xs-4,ys-4,xs+4,ys+4);
    end;
  end;
end;

procedure TLineInterpolateForm.ChartTool1Change(Sender: TCursorTool; x,
  y: Integer; const XValue, YValue: Double; Series: TChartSeries;
  ValueIndex: Integer);
var
  i: Integer;
begin
  xval := XValue;

  With Chart1.Title.Text do
  begin
    Clear;
    for i:=0 to Chart1.SeriesCount - 1 do
        Add(Chart1[i].Name + ': Y('+FloatToStrF(XValue, ffNumber, 8, 2)+')= ' +
            FloatToStrF(InterpolateLineSeries(Chart1[i],XValue), ffNumber, 8, 2)+#13#10);
  end;
end;

initialization
  RegisterClass(TLineInterpolateForm);
end.
单位线插值;
{$I TeeDefs.inc}
接口
使用
{$ifndeflinux}
窗口、消息、,
{$ENDIF}
系统、类、,
{$IFDEF CLX}
QGraphics、QControls、QForms、QDialogs、QExtCtrls、QstCtrls、QComCtrls、,
{$ELSE}
图形、控件、窗体、对话框、ExtCtrls、StdCtrls、ComCtrls、,
{$ENDIF}
底座、TeEngine、系列、TeeProcs、图表、TeeTools、TeeGDIPlus;
类型
TLineInterpolateForm=类(TBaseForm)
系列1:T系列;
复选框1:t复选框;
系列2:T系列;
系列3:T系列;
ChartTool1:TCursorTool;
图表工具2:TGridBandTool;
过程表单创建(发送方:ToObject);
程序图1后绘图(发送方:TObject);
过程图表工具1更改(发送方:TCursorTool;x,y:整数;
常量XValue,YValue:Double;系列:TChartSeries;
ValueIndex:整数);
私有的
{私有声明}
xval:Double;
函数插值系列(系列:TChartSeries;XValue:Double):Double;超载;
函数插值系列(系列:TChartSeries;FirstIndex,
LastIndex:Integer;XValue:Double:Double;超载;
公众的
{公开声明}
结束;
实施
{$IFNDEF CLX}
{$R*.DFM}
{$ELSE}
{$R*.xfm}
{$ENDIF}
过程tlineinterpolieform.FormCreate(发送方:TObject);
varⅠ:整数;
开始
继承;
对于i:=0到图表1.serieCount-1 do
图1[i]。填充样本值;
结束;
函数TLineInterpolateForm.InterpolateLineSeries(系列:TChartSeries;
XValue:Double:Double;
开始
结果:=插值系列(系列,系列。第一次显示索引,系列。最后一次值索引,X值);
结束;
函数TLineInterpolateForm.InterpolateLineSeries(系列:TChartSeries;
FirstIndex,LastIndex:Integer;XValue:Double:Double;
变量
索引:整数;
dx,dy:Double;
开始
对于索引:=从第一个索引到最后一个索引
如果Series.XValues.Value[Index]>XValue,则中断;
//保障
如果(Index=Series.Count),则Index:=Series.Count-1;
//y=(y2-y1)/(x2-x1)*(x-x1)+y1
dx:=Series.XValues.Value[Index]-Series.XValues.Value[Index-1];
dy:=Series.YValues.Value[Index]-Series.YValues.Value[Index-1];
如果(dx0)那么
结果:=dy*(XValue-Series.XValues.Value[Index-1])/dx+Series.YValues.Value[Index-1]
其他结果:=0;
结束;
程序TLINERPOINTERFORM.CHART1AFTREAW(发送方:TObject);
var xs,ys,i:整数;
开始
如果复选框1.选中,则
开始
xs:=Chart1.Axes.Bottom.CalcXPosValue(xval);
对于i:=0到图表1.serieCount-1 do
开始
ys:=Chart1[i].GetVertAxis.CalcPosValue(插值系列(Chart1[i],xval));
Chart1.Canvas.Brush.Color:=Chart1[i].Color;
图表1.画布.椭圆(xs-4,ys-4,xs+4,ys+4);
结束;
结束;
结束;
过程TLINEEInterpoleForm.ChartTool1Change(发送方:TCursorTool;x,
y:整数;常量XValue,YValue:双精度;系列:TChartSeries;
ValueIndex:整数);
变量
i:整数;
开始
xval:=XValue;
使用Chart1.Title.Text do
开始
清楚的
对于i:=0到图表1.serieCount-1 do
添加(图表1[i].Name+':Y('+FloatToStrF(XValue,ffNumber,8,2)+')='+
FloatToStrF(插值序列(图1[i],XValue),ffNumber,8,2)+13#10);
结束;
结束;
初始化
寄存器类(tlineinterpolitionform);
结束。

首先感谢您的快速回复。不幸的是,如果序列正好包含给定的日期,则Locate方法只提供有效的索引。在我的情况下,它是非常不可能传递一个日期的方法,而该系列恰恰包含。日期就在附近。我不明白为什么这个答案得到的喜欢太少。太棒了!这正是我想要避免做的:“或者我需要迭代整个系列直到我到达所选的日期吗?”。在您的代码中,您迭代序列的所有点,直到找到一个大于给定的
x
索引:=FirstIndex to LastIndex do if Series.XValues.Value[Index]>XValue的
。如果您有大约100k个数据点,则速度会很慢。因此,二进制搜索是最好的解决方案。@Florianschunk当然。这只是一个选择系列与小点。
unit Line_Interpolate;
{$I TeeDefs.inc}

interface

uses
  {$IFNDEF LINUX}
  Windows, Messages,
  {$ENDIF}
  SysUtils, Classes,
  {$IFDEF CLX}
  QGraphics, QControls, QForms, QDialogs, QExtCtrls, QStdCtrls, QComCtrls,
  {$ELSE}
  Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, ComCtrls,
  {$ENDIF}
  Base, TeEngine, Series, TeeProcs, Chart, TeeTools, TeeGDIPlus;

type
  TLineInterpolateForm = class(TBaseForm)
    Series1: TLineSeries;
    CheckBox1: TCheckBox;
    Series2: TLineSeries;
    Series3: TLineSeries;
    ChartTool1: TCursorTool;
    ChartTool2: TGridBandTool;
    procedure FormCreate(Sender: TObject);
    procedure Chart1AfterDraw(Sender: TObject);
    procedure ChartTool1Change(Sender: TCursorTool; x, y: Integer;
      const XValue, YValue: Double; Series: TChartSeries;
      ValueIndex: Integer);
  private
    { Private declarations }
    xval: Double;
    function InterpolateLineSeries(Series: TChartSeries;XValue: Double): Double; overload;
    function InterpolateLineSeries(Series: TChartSeries; FirstIndex,
                                  LastIndex: Integer; XValue: Double): Double; overload;
  public
    { Public declarations }
  end;

implementation

{$IFNDEF CLX}
{$R *.DFM}
{$ELSE}
{$R *.xfm}
{$ENDIF}

procedure TLineInterpolateForm.FormCreate(Sender: TObject);
var i: Integer;
begin
  inherited;

  for i:=0 to Chart1.SeriesCount-1 do
    Chart1[i].FillSampleValues;
end;

function TLineInterpolateForm.InterpolateLineSeries(Series: TChartSeries;
  XValue: Double): Double;
begin
  result:=InterpolateLineSeries(Series,Series.FirstDisplayedIndex,Series.LastValueIndex,XValue);
end;

function TLineInterpolateForm.InterpolateLineSeries(Series: TChartSeries;
  FirstIndex, LastIndex: Integer; XValue: Double): Double;
var
  Index: Integer;
  dx,dy: Double;
begin
  for Index:=FirstIndex to LastIndex do
    if Series.XValues.Value[Index]>XValue then break;

  //safeguard
  if (Index<1) then Index:=1
  else if (Index>=Series.Count) then Index:=Series.Count-1;

  // y=(y2-y1)/(x2-x1)*(x-x1)+y1
  dx:=Series.XValues.Value[Index] - Series.XValues.Value[Index-1];
  dy:=Series.YValues.Value[Index] - Series.YValues.Value[Index-1];

  if (dx<>0) then
    result:=dy*(XValue - Series.XValues.Value[Index-1])/dx + Series.YValues.Value[Index-1]
  else result:=0;
end;

procedure TLineInterpolateForm.Chart1AfterDraw(Sender: TObject);
var xs, ys, i: Integer;
begin
  if CheckBox1.Checked then
  begin
    xs := Chart1.Axes.Bottom.CalcXPosValue(xval);

    for i:=0 to Chart1.SeriesCount - 1 do
    begin
      ys := Chart1[i].GetVertAxis.CalcYPosValue(InterpolateLineSeries(Chart1[i],xval));
      Chart1.Canvas.Brush.Color := Chart1[i].Color;
      Chart1.Canvas.Ellipse(xs-4,ys-4,xs+4,ys+4);
    end;
  end;
end;

procedure TLineInterpolateForm.ChartTool1Change(Sender: TCursorTool; x,
  y: Integer; const XValue, YValue: Double; Series: TChartSeries;
  ValueIndex: Integer);
var
  i: Integer;
begin
  xval := XValue;

  With Chart1.Title.Text do
  begin
    Clear;
    for i:=0 to Chart1.SeriesCount - 1 do
        Add(Chart1[i].Name + ': Y('+FloatToStrF(XValue, ffNumber, 8, 2)+')= ' +
            FloatToStrF(InterpolateLineSeries(Chart1[i],XValue), ffNumber, 8, 2)+#13#10);
  end;
end;

initialization
  RegisterClass(TLineInterpolateForm);
end.