Page 1 of 1

displaying individual failure marks

Posted: Wed Dec 13, 2006 1:05 am
by 9347662
Hi,
I am using Borland Delphi 2005 and am currently comparing two series where one will be the default and the other is tested for failures. I would like individual marks to appear at the point of failure and display 'Failed' when it fails compared to the default series. Is this possible? Thank you.
David

Posted: Wed Dec 13, 2006 7:59 am
by Marjan
Hi, David.

Yes, several ways to do it. I'd use TChartSeries OnGetMarkText event to show/hide individual mark text. Something like this:

Code: Select all

procedure TForm1.Series2GetMarkText(Sender: TChartSeries; ValueIndex: Integer;
  var MarkText: string);
begin
  if Sender.MandatoryValueList[ValueIndex] >0 then MarkText := ''
  else MarkText := 'Failure';
end;
In the example above series YValues[ValueIndex] is compared with zero. If false, then a "Failure" mark text is shown, otherwise no mark text is shown. The same approach can be used to check failure/success for individual series points.

Posted: Fri Dec 15, 2006 12:50 am
by 9347662
Hi
Thanks for the reply. How do you do it if you want to activate the failure detection when the checkbox is clicked? I cant seem to get your code working. How does it actually activate?

Posted: Fri Dec 15, 2006 7:33 am
by Marjan
Hi.

How does it work? Well, you're using the TChartSeries OnGetMarkText event, together with failure series values, to "filter" which point marks you want to mark as "failed". Something like this:

Code: Select all

// Enable, disable failure filter
procedure TForm1.CheckBox1Clicked(Sender: TObject);
begin
  if (CheckBox1.Checked) then Series2.OnGetMarkText := Series2GetMarkText;
  else Series2.OnGetMarkText := nil;
end;

// Series "Failure filter" event
procedure TForm1.Series2GetMarkText(Sender: TChartSeries; ValueIndex: Integer; var MarkText: string); 
begin 
  if Not(PointFailed(Series.MandatoryValueList[ValueIndex])) then MarkText := '' 
  else MarkText := 'Failure'; 
end;
where PointFailed is your failure/success boolean function (I don't know your failure criteria so you'll have to code it yourself).

Posted: Tue Dec 19, 2006 4:42 am
by 9347662
Hi,

I have tried out your code. Can't seem to get it working. Below is mine:

Code: Select all

procedure TForm1.openpassfailClick(Sender: TObject);
begin
  if openpassfail.Checked = False then
    begin
      for I:= 16 to 18 do
        Chart3.Series[I].Clear;
        Series1.Clear;
        Series2.OnGetMarkText:= nil;
    end
  else
    begin
      for I:= 16 to 18 do
        Chart3.Series[I].Clear;
      OpenShift:= FloatSpinEdit1.Value;
      Series2.OnGetMarkText:= Series2GetMarkText;
      A:= plotshiftx.Value;
      B:= plotshifty.Value;
      x_axis_multi(x);
      AssignFile(YFile, CDMulti2.Text); //assign filehandle NFile to Edit6.Text
      G:= autofreqmulti(G);
      xfreqmulti:= (0.818/(G*0.4));
      Reset(XFile); //open XFile for read access
        while not Eof(XFile) do //keep looping until the end of XFile
          begin
            Readln(XFile, x); //read line from file to x
            Chart3.Series[16].AddXY((x*xfreqmulti), OpenMaxMinMid + OpenShift, '', clTeeColor); //plot graph
            Chart3.Series[17].AddXY((x*xfreqmulti), OpenMaxMinMid + OpenShift + 0.3, '', clTeeColor); //plot graph
            Chart3.Series[18].AddXY((x*xfreqmulti), OpenMaxMinMid + OpenShift - 0.4, '', clTeeColor); //plot graph
          end;
      for J:= 0 to 400 do
        if (OpenMaxMinMid + OpenShift + 0.3) < (QuickLoadBuffY[J] + B) then
          begin
            Series1.AddXY(QuickLoadBuffX[J] + A, QuickLoadBuffY[J] + B, '', clTeeColor);
          end;
      for J:= OMax to 400 do
        if (OpenMaxMinMid + OpenShift - 0.4) > (QuickLoadBuffY[J] + B) then
          begin
            Series1.AddXY(QuickLoadBuffX[J] + A, QuickLoadBuffY[J] + B, '', clTeeColor);
          end;
      CloseFile(XFile);
    end;
end;

procedure TForm1.Series2GetMarkText(Sender: TChartSeries; ValueIndex: Integer;
  var MarkText: string);
begin
  for ValueIndex:= 0 to 400 do
        if (OpenMaxMinMid + OpenShift + 0.3) < (QuickLoadBuffY[ValueIndex] + B) then
          begin
            MarkText:= 'Failure';
    end;
   for ValueIndex:= OMax to 400 do
        if (OpenMaxMinMid + OpenShift - 0.4) > (QuickLoadBuffY[ValueIndex] + B) then
          begin
            MarkText:= 'Failure';
    end;
end;

Posted: Tue Dec 19, 2006 7:32 am
by Marjan
Hi.

I think the problem is how you use ValueIndex parameter in OnGetMarkText event. In this event ValueIndex is constant parameter and should not be used as variable in for loop.

You should figure out another way to "connect" failure to point ValueIndex (index) parameter. Something like this:

Code: Select all

  if (OpenMaxMinMid + OpenShift + 0.3) < (QuickLoadBuffY[ValueIndex]+ B) or  OpenMaxMinMid + OpenShift - 0.4) > (QuickLoadBuffY[ValueIndex] + B) 
  then MarkText:= 'Failure';
Of course, ValueIndex runs from 0 to number of points in series-1 so perhaps it's a better idea to use Series.YValues[ValueIndex] instead of QuickLoadBuffY[ValueIndex] to check for failure.

Posted: Tue Dec 19, 2006 11:05 pm
by 9347662
Hi,

Thanks for the reply. I was not familiar with the functionality of the ValueIndex and therefore tried to use it as a counter. I initially had

Code: Select all

J:= 0 to 400 
where I had 819 samples. I tried using Series2.YValues instead and nothing shows up. What I am thinking is that the Series2GetmarkText is not being executed. Is

Code: Select all

Series2.OnGetMarkText:= Series2GetMarkText
executing the code? Do you have a simple code or complied file that I can use to test out? If so that would be very helpful. Thank you.

David

Posted: Wed Dec 20, 2006 7:03 am
by Marjan
Hi.

Hmm... Try setting Series2.Marks.Visible property to true:

Code: Select all

Series2.Marks.Visible := True;
Series2.OnGetMarkText := Series2GetMarkText;
If this doesn't work, let me know and I'll prepare a sample test application (D2006) for you.

Posted: Wed Dec 20, 2006 10:51 pm
by 9347662
Hi,

Thanks for that code. It works but it displays 'Failure' at every point, even sections that don't fail. I will continue to try and solve this problem but a sample code would definitely help. Your help is much appreciated. Thank you.

David

Posted: Tue Jan 09, 2007 12:25 pm
by 9347662
Hi,
Have been trying various different ways but it all end up displayed together. It is operating like the original marks function where it is displayed along the whole line. Maybe you misunderstood. What I am trying to do is actually just display single failure marks where the line has failed, otherwise, other sections of the line will display nothing. I do not want to display failure all over the line whenever there is a failure. Thank you.
David

Posted: Tue Jan 09, 2007 1:03 pm
by Marjan
Hi.
It works but it displays 'Failure' at every point, even sections that don't fail.
This would indicate that the failure check you perfom in series OnGetMarkText always returns true i.e. "Failure" is displayed for every point.
I've prepared a small test application demonstrating how you can test for failure. In the example below Series1 holds default data and Series2 holds actual data which is then compared to default data (Series1.YValues) for failures. In this example a failure occurs only if difference between default and actual value is greater than 2.0.

Code: Select all

procedure TForm1.FormCreate(Sender: TObject);
begin
  // Populate series
  // Series1 = default values
  Series1.Add(10);
  Series1.Add(12);
  Series1.Add(3);
  Series1.Add(7);
  Series1.Add(8);
  // Series2 = actual data
  Series2.Add(8);
  Series2.Add(11);
  Series2.Add(7);
  Series2.Add(7);
  Series2.Add(6);
  // Signal failure if difference between
  // default value and actual data is >= 2
  Series2.Marks.Visible := True;

  // The end result
  // Series2 will display three "Failure" marks:
  // fist point (10-8), third point (3-7), fifth point (8-6).
end;

procedure TForm1.Series2GetMarkText(Sender: TChartSeries; ValueIndex: Integer;
  var MarkText: string);
var absdiff: double;
begin
  // Point absolute difference
  // we use this to test for failure
  // NOTE : this will work only if default series and actual series
  // have the same number of points. Otherwise you CAN'T do failure check here.
  absdiff := Abs(Sender.YValues[ValueIndex] - Series1.YValues[ValueIndex]);
  if (absdiff>=2.0) then MarkText := 'Failure' else MarkText := '';
end;
I hope this will clarify what I meant with my original post.

Posted: Tue Jan 09, 2007 11:56 pm
by 9347662
Hi,
From my previous code above

Code: Select all

procedure TForm1.Series2GetMarkText(Sender: TChartSeries; ValueIndex: Integer;
  var MarkText: string);
begin
  for J:= 0 to 400 do
        if (OpenMaxMinMid + OpenShift + 0.3) < (QuickLoadBuffY[J] + B) then
          begin
            MarkText:= 'Failure';
          end
        else
          begin
            MarkText:= '';
          end;
   for J:= OMax to 400 do
        if (OpenMaxMinMid + OpenShift - 0.4) > (QuickLoadBuffY[J] + B) then
          begin
            MarkText:= 'Failure';
     end
        else
          begin
            MarkText:= '';
          end;
end;
 
What I am trying to do is actually check for failures from 0 to 400 and OMax to 400. I am not comparing a series but rather values which are stored in the buffer I called QuickLoadBuffY[J] which is plotted as a series. Basically there are two reference points, one is 0.3 above the mid point and one is o.4 below the mid point. Anything within that reference point will pass, all else will fail within the specified range. I have a total of 818 points and only need to compare up to 400. Is that possible?
David

Posted: Fri Jan 12, 2007 3:15 pm
by narcis
Hi David,

Could you please send us a simple example project we can run "as-is" to reproduce the problem here? You can post your files at news://www.steema.net/steema.public.attachments newsgroup.

Thanks in advance.