Recent

Author Topic: [SOLVED] TAChart - lineColor - what property to use  (Read 1124 times)

bnl

  • New Member
  • *
  • Posts: 15
[SOLVED] TAChart - lineColor - what property to use
« on: August 04, 2020, 07:38:26 pm »
Hi!
I have a Treeview which I fill with a key (to a database)
When selectionChanged in that  TreeView I was to
use that key to draw a graph.
It is a simple line graph
I have 8 - 16 series,
and I want 1 to have a special color (green)
and the rest should have line color red.

I create the series dynamically and add to the graph.
All is well - but for line color.
I tried these three properties
Code: Pascal  [Select][+][-]
  1.    
  2.     Series[cnt].LinePen.Color := clRed;
  3.     Series[cnt].SeriesColor:= clRed     ;
  4.     Series[cnt].Pointer.Pen.Color := clRed   ;
  5.  

and no matter how I do I usually get 1 green, 1 red and the rest black.


here an excerpt from it.
How should I do instead ?


Code: Pascal  [Select][+][-]
  1.  
  2. type
  3.  
  4.   { TForm1 }
  5.  
  6.   TForm1 = class(TForm)
  7.     Button1: TButton;
  8.     Button2: TButton;
  9.     Chart1: TChart;
  10.     Chart1LineSeries1: TLineSeries;
  11.     Edit1: TEdit;
  12.     Edit2: TEdit;
  13.     TrackBar1: TTrackBar;
  14.     TreeView1: TTreeView;
  15.     procedure Button1Click(Sender: TObject);
  16.     procedure Button2Click(Sender: TObject);
  17.     procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
  18.     procedure FormCreate(Sender: TObject);
  19.  
  20.     procedure TreeView1SelectionChanged(Sender: TObject);
  21.   private
  22.     procedure DrawGraph(marketid: string);
  23.  
  24.   public
  25.  
  26.   end;                                              
  27.  
  28.  
  29. var
  30.   Form1: TForm1;
  31.   T: TSQLTransaction;
  32.   All_Markets, runner_price_data, runners_in_race: TSQLQuery;
  33.   PQConn: TPQConnection;
  34.   Series: array[0..15] of TLineSeries;                  
  35.  

this is the bulk of it

Code: Pascal  [Select][+][-]
  1.   while not runners_in_race.EOF do begin
  2.     cnt := cnt + 1;
  3.     selectionid := runners_in_race.FieldByName('selectionid').AsInteger;
  4.     placement := runners_in_race.FieldByName('status').AsString;
  5.     runner_price_data.params.parambyname('marketid').AsString := marketid;
  6.     runner_price_data.params.parambyname('selectionid').AsInteger := selectionid;
  7.     edit1.Text := IntToStr(selectionid);
  8.  
  9.     runner_price_data.Prepare;
  10.     runner_price_data.Open;
  11.     x := 0.0;
  12.     Series[cnt] := TLineSeries.Create(Chart1);
  13.     Series[cnt].BeginUpdate;
  14.  
  15.     if placement = 'WINNER' then begin
  16.       Series[cnt].LinePen.Color := clGreen;
  17.    //   Series[cnt].SeriesColor:= clGreen   ;
  18.     //  Series[cnt].Pointer.Pen.Color := clGreen   ;
  19.     end
  20.     else if placement = 'LOSER' then begin
  21.       Series[cnt].LinePen.Color := clRed;
  22.      // Series[cnt].SeriesColor:= clRed     ;
  23.    //   Series[cnt].Pointer.Pen.Color := clRed   ;
  24.     end
  25.     else begin
  26.       Series[cnt].LinePen.Color := clPurple;
  27.    //   Series[cnt].SeriesColor:= clPurple  ;
  28.    //   Series[cnt].Pointer.Pen.Color := clPurple   ;
  29.     end;
  30.  
  31. //    while not runner_price_data.EOF and (cnt <= length(Series)) do begin
  32.     while not runner_price_data.EOF do begin
  33.       x := x + 1.0;
  34.       backprice := runner_price_data.FieldByName('backprice').AsFloat;
  35.       if backprice <= Real(pos) then
  36.         Series[cnt].AddXy(x, backprice)
  37.       else
  38.         Series[cnt].AddXy(x, Real(pos));
  39.  
  40.       runner_price_data.Next;
  41.     end;
  42.     runner_price_data.Close;
  43.     Series[cnt].EndUpdate;
  44.     Chart1.AddSeries(Series[cnt]);
  45.  
  46.     runners_in_race.Next;
  47.   end;
  48.  
  49.  


thanks
/Björn
« Last Edit: August 11, 2020, 05:11:58 pm by bnl »

wp

  • Hero Member
  • *****
  • Posts: 7551
Re: TAChart - lineColor - what property to use
« Reply #1 on: August 04, 2020, 09:59:35 pm »
This is not enough information. Please make a copy of your project and strip everything which is not needed so that only essential parts to reproduce the issue are left. Pack the pas, lfm, lpi, lpr and data files into a shared zip which you can upload under "Attachment and other options" (do not include the exe, res, ppu, o and other compiler-generated files because the upload may become too large otherwise). And use only a simple data base format (sqlite4, dbase, csv) - I don want to install a database server just to answer this question.
Mainly Lazarus trunk / fpc 3.2.0 / all 32-bit on Win-10, but many more...

bnl

  • New Member
  • *
  • Posts: 15
Re: TAChart - lineColor - what property to use
« Reply #2 on: August 05, 2020, 09:41:56 am »
Ok, thanks for wanting to help.
I see I did not mention any versions.
I'm on macOS 10.13.6 (High Sierra) with Lazarus 2.0.6 and freepascal 3.0.4

Instead of migrating the data to another database, I created a read-only user which is in the code (function CreateConnection).
It is reachable from the internet.

compile, start and open the treeview to the left,
then click on any entry in the list.
I want 1 green line, the rest red.
However most get black (and not purple as the code indicates if the if statement at line 137 fails - which is does not - I followed it with debug)



bnl

  • New Member
  • *
  • Posts: 15
Re: TAChart - lineColor - what property to use
« Reply #3 on: August 05, 2020, 09:51:03 am »
Here's an attached screenshot. Interestingly, the colors of the legend (top right corner) seems correct
/Björn

wp

  • Hero Member
  • *****
  • Posts: 7551
Re: TAChart - lineColor - what property to use
« Reply #4 on: August 05, 2020, 06:10:34 pm »
Instead of migrating the data to another database, I created a read-only user which is in the code (function CreateConnection).
It is reachable from the internet.
But I need to install PostgreSQL, at least on Windows and on the Linux that I tested. I downloaded the libpq.dll and stored it in the exe folder of you your demo, no success. Please understand that I do not want to install (and learn) big database client software on my system (and VMs) which I don't need, just to answer a forum question.
Mainly Lazarus trunk / fpc 3.2.0 / all 32-bit on Win-10, but many more...

bnl

  • New Member
  • *
  • Posts: 15
Re: TAChart - lineColor - what property to use
« Reply #5 on: August 05, 2020, 06:53:20 pm »
Quote
But I need to install PostgreSQL,

Hmm, yes. I didn't think of that  - sorry.
I've been digging around the forum and seen some with
similar - but not identical - problems on osx.
It may be a cocoa problem.
Anyway, when I get home (tomorrow ) I''ll try to make a small
reproducible. Thinking of It - I don't think I need a db at all to reproduce.
Thanks for the effort
/Björn 

bnl

  • New Member
  • *
  • Posts: 15
Re: TAChart - lineColor - what property to use
« Reply #6 on: August 06, 2020, 02:03:27 pm »
ok - new project with no db
run it and press Draw-button top left.
I seem to often get a BLACK line or two as well
The code should give no reason fo a black line at all

Code: Pascal  [Select][+][-]
  1.  
  2. procedure TForm1.Button1Click(Sender: TObject);
  3. var
  4.  cnt : integer;
  5.    x : real;
  6.    r : real;
  7.    i,j : integer;
  8. begin
  9.   cnt := 0;
  10.   for i := 1 to 5 do begin
  11.      x := 0.0;
  12.      //Series[cnt]
  13.      Series[cnt] := TLineSeries.Create(Chart1);
  14.      Series[cnt].BeginUpdate;
  15.      r := Random;
  16.  
  17.      if r < 0.2 then begin
  18.        Series[cnt].LinePen.Color := clGreen;
  19.     ////   Series[cnt].SeriesColor:= clGreen   ;
  20.     // //  Series[cnt].Pointer.Pen.Color := clGreen   ;
  21.      end
  22.      else if r < 0.4 then begin
  23.        Series[cnt].LinePen.Color := clRed;
  24.     //  // Series[cnt].SeriesColor:= clRed     ;
  25.     ////   Series[cnt].Pointer.Pen.Color := clRed   ;
  26.      end
  27.      else begin
  28.        Series[cnt].LinePen.Color := clPurple;
  29.     ////   Series[cnt].SeriesColor:= clPurple  ;
  30.     ////   Series[cnt].Pointer.Pen.Color := clPurple   ;
  31.      end;
  32.  
  33.      for j := 1 to 5 do begin
  34.        x := x + 1.0;
  35.        Series[cnt].AddXy(x, j*r)
  36.      end ; //loop
  37.  
  38.      Series[cnt].EndUpdate;
  39.      Chart1.AddSeries(Series[cnt]);
  40.      cnt := cnt +1;
  41.   end; //loop
  42.  
  43. end;                  
  44.  

As I mentioned before:
imac:~ bnl$ uname -a
Darwin imac.lan 17.7.0 Darwin Kernel Version 17.7.0: Thu Jun 18 21:21:34 PDT 2020; root:xnu-4570.71.82.5~1/RELEASE_X86_64 x86_64
(High Sierra - 10.13.6)

Lazarus 2.0.6
fpc 3.0.4


/Björn

wp

  • Hero Member
  • *****
  • Posts: 7551
Re: TAChart - lineColor - what property to use
« Reply #7 on: August 06, 2020, 10:33:20 pm »
Thank you -- this is the kind of demo that I can work with.

I tested the project on Windows - everything correct. Then I tried on a VM with macOS 10.14.3 which is painfull slow, but I seems that it is working correctly, too.

One, maybe stupid, note: I noticed that it is a bit difficult to distingush clPurple from clBlack, at least on my monitor. Could you use clYellow instead -- it will definitely make a big difference.

The other note: This issue reminds me of a recent, still unsolved, issue discussed in https://forum.lazarus.freepascal.org/index.php/topic,48842.0.html. In this issue the brush color is changed but not always propagated to the macOS drawing engine. Looks as if we have the same issue here, now with the pen.

Let me investigate further...
Mainly Lazarus trunk / fpc 3.2.0 / all 32-bit on Win-10, but many more...

bnl

  • New Member
  • *
  • Posts: 15
Re: TAChart - lineColor - what property to use
« Reply #8 on: August 06, 2020, 10:51:42 pm »
Quote
The other note: This issue reminds me of a recent, still unsolved, issue discussed in https://forum.lazarus.freepascal.org/index.php/topic,48842.0.html. In this issue the brush color is changed but not always propagated to the macOS drawing engine. Looks as if we have the same issue here, now with the pen.

Yes, not exactly the same but similar.

Three screenshoots attached, in two I've changed purple -> yellow. Still black lines appear.
And in the last one, I also show the legend - which gets the colors correct.
1 green
1 red
3 yellow
while the graph itself has
1 green
1 red
2 black
1 yellow

/Björn

wp

  • Hero Member
  • *****
  • Posts: 7551
Re: TAChart - lineColor - what property to use
« Reply #9 on: August 06, 2020, 11:11:23 pm »
Please try the following code which avoids the random numbers to get reproducible results.
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button3Click(Sender: TObject);
  2. const
  3.   COLORS: array[1..5] of TColor = (clRed, clGreen, clBlue, clYellow, clPurple);
  4. var
  5.   cnt: Integer;
  6.   ser: TLineseries;
  7. begin
  8.   Chart1.ClearSeries;
  9.   for cnt := 1 to 5 do
  10.   begin
  11.      ser := TLineSeries.Create(Chart1);
  12.      ser.SeriesColor := COLORS[cnt];
  13.      ser.Title := IntToStr(cnt);
  14.      ser.AddXY(0, cnt);
  15.      ser.AddXY(1, cnt+1);
  16.      Chart1.AddSeries(ser);
  17.   end;
  18. end;

Play with the colors in tha COLORS array. You should also try a combination which contains three consecutive yellow colors. I suspect that setting a color to one which has been previously set is not working; this is the issue in the brush.color case.

[EDIT]
I could reproduce the issue on macOS when I select the following colors in above array: clred, clBlue, clYellow, clYellow, clYellow; only the center yellow line is correct, the others are black.
« Last Edit: August 07, 2020, 12:16:34 am by wp »
Mainly Lazarus trunk / fpc 3.2.0 / all 32-bit on Win-10, but many more...

bnl

  • New Member
  • *
  • Posts: 15
Re: TAChart - lineColor - what property to use
« Reply #10 on: August 07, 2020, 02:35:53 pm »
Quote
I could reproduce the issue on macOS when I select the following colors in above array: clred, clBlue, clYellow, clYellow, clYellow; only the center yellow line is correct, the others are black.

Hmm, so can I. But not in the same way.
I get (from bottom and up) red, blue,BLACK,yellow,BLACK
Or is that what you mean by the center yellow?
(I interpret 'center yellow line' as the 3rd line, and that that one is yellow, but it could be the 4th as well , the one in center of the should-be-yellow lines)

I'll attach a screenshot as well

/Björn



wp

  • Hero Member
  • *****
  • Posts: 7551
Re: TAChart - lineColor - what property to use
« Reply #11 on: August 07, 2020, 02:39:20 pm »
Yes, exactly like here.
Mainly Lazarus trunk / fpc 3.2.0 / all 32-bit on Win-10, but many more...

bnl

  • New Member
  • *
  • Posts: 15
Re: TAChart - lineColor - what property to use
« Reply #12 on: August 07, 2020, 02:49:09 pm »
Quote
Play with the colors in tha COLORS array. You should also try a combination which contains three consecutive yellow colors. I suspect that setting a color to one which has been previously set is not working; this is the issue in the brush.color case.

Not quite - or it is nob obvious to me.
I set the array to red,blue,red,blue,red,blue (and increased it to 6 elements)
This was fine
but
red,red,red,blue,blue,blue is not.
Only the FIRST occurrence works, the others are black.
so it became
red,BLACK,BLACK, blue,BLACK,BLACK

with the yellow ones, the SECOND occurrence was correct, but not the first

I'll attach these screenshot as well. The legend shows how it was intended

/Björn

wp

  • Hero Member
  • *****
  • Posts: 7551
Re: TAChart - lineColor - what property to use
« Reply #13 on: August 07, 2020, 04:04:54 pm »
Yes I don't understand the sequence of "correct" and "black" either.

But I found a workaround in the mean-time: When you open unit TADrawerCanvas.pas (in folder "components/tachart" of your Lazarus installation), find TCanvasDrawer.SetPen and, in the "else" part of the "if FXor" instruction add code which makes sure that the Pen.Color is different from the new value:

Code: Pascal  [Select][+][-]
  1. procedure TCanvasDrawer.SetPen(APen: TFPCustomPen);
  2. begin
  3.   with GetCanvas do begin
  4.     if FXor then begin
  5.       ...
  6.     end
  7.     else begin
  8.       {$ifdef LCLCocoa}   // ADD THIS FROM HERE...
  9.       // Workaround for series color issue in cocoa: make sure that color is different
  10.       if Pen.Color = clWhite then
  11.         Pen.Color := clBlack
  12.       else
  13.         Pen.Color := clWhite;
  14.       {$endif}    // ... TO HERE
  15.  
  16.       if APen is TPen then
  17.         Pen.Assign(APen)
  18.       else  begin
  19.         Pen.Color := FPColorToChartColor(APen.FPColor);
  20.         ...
  21.       end;
  22.     ....
  23.   end;
  24. end;

The reason is that for some reason (which I don't understand) the pen must call FreeReference in Cocoa before changing a color, but this does not happen because the TPen's Color setter code is exited immediately when the LCL color value does not change.

After this modification recompile the TAChart package, and the series colors will be correct.

Of course, this is only a workaround which will probably slow down execution of TAChart on cocoa.  The real cause must be somewhere in the widgetset part of LCL graphics. Unfortinately I do not understand anything about the internals of macOS and its graphics. For a bug report I need a very simple example without TAChart (which is too complex). Something like this OnPaint code for a Paintbox on a form:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.PaintBox1Paint(Sender: TObject);
  2. var
  3.   y: Integer;
  4. begin
  5.   with Paintbox1 do
  6.   begin
  7.     Canvas.Brush.Color := clWhite;
  8.     Canvas.FillRect(0, 0, Width,Height);
  9.  
  10.     Canvas.Pen.Color := clRed;
  11.     Canvas.Line(0, y, Width, y);
  12.  
  13.     inc(y, 5);
  14.     Canvas.Pen.Color := clYellow;
  15.     Canvas.Line(0, y, Width, y);
  16.  
  17.     // What to do here to break the pen.Reference?
  18.  
  19.     inc(y, 5);
  20.     Canvas.Pen.Color := clYellow;
  21.     Canvas.Line(0, y, Width, y);
  22.  
  23.     inc(y, 5);
  24.     Canvas.Pen.Color := clYellow;
  25.     Canvas.Line(0, y, Width, y);
  26.  
  27.     inc(y, 5);
  28.     Canvas.Pen.Color := clYellow;
  29.     Canvas.Line(0, y, Width, y);
  30.   end;
  31. end;

As expected this code is working correctly, 1 red and 4 yellow lines. Something is happening in TAChart which breaks the pen's reference. When we find something to insert between the 1st and 2nd yellow line drawing code which makes the subsequent yellow lines to be drawn in black, we have a good example for the bug report.
Mainly Lazarus trunk / fpc 3.2.0 / all 32-bit on Win-10, but many more...

bnl

  • New Member
  • *
  • Posts: 15
Re: TAChart - lineColor - what property to use [SOLVED/work-around]
« Reply #14 on: August 07, 2020, 04:44:54 pm »
Quote
But I found a workaround in the mean-time

Thanks, that did the trick.
While a work-around, it sure is good enough for me.
Thanks again for you time and effort
/Björn

 

TinyPortal © 2005-2018