Ternary Graph Assigning the Weighting parameter

TeeChart VCL for Borland/CodeGear/Embarcadero RAD Studio, Delphi and C++ Builder.
Errol
Newbie
Newbie
Posts: 29
Joined: Mon Jul 08, 2019 12:00 am

Re: Ternary Graph Assigning the Weighting parameter

Post by Errol » Thu Sep 19, 2019 5:49 am

Hello Marc
Thank you for your reply. When do you think the revised code will be available?

I have compared our code (both for a line series and a ternary series), with the test program provided by you where data is loaded from a csv file. In our code, the series is empty, even though the datasource is defined, and is presumably populated from the dataset when the graph is drawn. This works for a line series but fails for a ternary series. In the test program, the ternary series is manually populated with data and so a ternary chart is drawn.

I have two questions:
1. Is there a way to populate the ternary series from the dataset before the graph is drawn? This would solve our problem in the short term.
2. Will the revised code overcome this problem, and make a ternary series behave more like a regular line series?

I look forward to your comments.

Best regards

Errol

Marc
Site Admin
Site Admin
Posts: 1272
Joined: Thu Oct 16, 2003 4:00 am
Location: Girona
Contact:

Re: Ternary Graph Assigning the Weighting parameter

Post by Marc » Thu Sep 19, 2019 3:19 pm

Hello Errol,

We can add AddXY overloads for the Ternary if the values being used are percentages and don't need to be derived.

Taking your proposal:
Then if there was a procedure to calculate A% and B% from A, B and C and plot A% on the Y-axis and B% on the left axis, the results would be the same. Of course it would be necessary to draw the B-axis on the right, and overwrite the bottom axis with the reverse C axis, but that can be easily done. This is the approach of most scientific graphing applications.
We are assuming then, that A and B are already percentages so C is simple 100-B-A.

For example, for the first record of your test data, it would read as below:
Sample Site: AT-303
Sample Date: 27/04/2007
Na/1000: 29.56252908 (%)
Sqrt(Mg): 4.30282624 (%)
K/100: 100 - Na/1000 - Sqrt(Mg) = 66,13464468
I think I haven't fully understood the following yet:
Of course it would be necessary to draw the B-axis on the right, and overwrite the bottom axis with the reverse C axis
but I include a plot made with the latest code, that takes in two variables, x and y, to make the plot that I see similar to the example you posted in an earlier post. If this doesn't meet the requirement please let us know what changes are required, maybe even improvising points hand drawn on the image to reinforce the idea.
Ternary3.png
Ternary3.png (48.55 KiB) Viewed 22206 times
With thanks.
Regards,
Marc
Steema Support

Errol
Newbie
Newbie
Posts: 29
Joined: Mon Jul 08, 2019 12:00 am

Re: Ternary Graph Assigning the Weighting parameter

Post by Errol » Fri Sep 20, 2019 5:53 am

Hi Marc

Thank you for your email. In my previous post, I was trying to explain that any point on a ternary graph can be plotted on a normal XY chart that has the left axis at an angle of 60°. The B% value is plotted on the bottom axis (with a left-to-right scale of 0 to 100) along a line parallel to the left axis. The A% value is plotted on the left axis along a horizontal line parallel to the bottom axis. The C value is used only to calculate the relative percentages, not for plotting.

To make this XY chart look like a conventional ternary chart, it will be necessary to draw the B axis from the top vertex to the right vertex with a scale from 0 to 100, and the C axis from the right vertex to the left vertex with a reverse scale from 0 to 100. But these axes are simply drawn on, the actual plotting uses the under-lying bottom axis and left axis.

I wish to report an apparent error. I have attached a test program, importing data directly from a csv file and the same data via a kbmmemtable. I have used artificial data where the B value is 5% for all samples. The data also has a strongly varying Weight value. I have also attached two images to show how the data should be plotted and how it is actually plotted. Calculations show that the program is using the Weighting value instead of the YValue, for both the direct entry from the csv file and via a kbmmemtable.

I am also concerned that if no Weighting value is defined, the ternary chart is not drawn, without any warning or error. The weighting parameter is surely not that important - if not defined, it should be set to a constant value (0 or 1) for all data points.

I look forward to your comments.

Best regards

Errol
Attachments
TernaryPlotResults.jpg
Top charts correct, bottom charts incorrect
TernaryPlotResults.jpg (241.54 KiB) Viewed 22204 times
TernaryGraph_kbmMemTable.zip
Ternary Chart test program
(35.14 KiB) Downloaded 1152 times

Marc
Site Admin
Site Admin
Posts: 1272
Joined: Thu Oct 16, 2003 4:00 am
Location: Girona
Contact:

Re: Ternary Graph Assigning the Weighting parameter

Post by Marc » Fri Sep 20, 2019 10:33 am

Hello Errol,

Thanks for the confirmation of use.

I have emailed you the earlier test project you uploaded, modified to use the new TeeChart units (also included) that now reproduce the charts you have requested.

Changes:
- Multiple Ternary Series supported without need for custom Axis code (http://bugs.teechart.net/show_bug.cgi?id=2231)
- two variable input supported (x,y) http://bugs.teechart.net/show_bug.cgi?id=2239
- No weighting needed when importing via SeriesTextSource (bugfix http://bugs.teechart.net/show_bug.cgi?id=2240)

*Note
A new property "DeriveZ := True;" is required if the data is being imported via datasets with only two of the three possible valuesets (ie x & y). When using add overloaded methods, setting the property is not required.

The last point is one I came across in earlier tests (see notes on mandatory-valuelist earlier in this thread) and answers your point:
" program is using the Weighting value instead of the YValue"

Regards,
Marc
Steema Support

Errol
Newbie
Newbie
Posts: 29
Joined: Mon Jul 08, 2019 12:00 am

Re: Ternary Graph Assigning the Weighting parameter

Post by Errol » Mon Sep 23, 2019 5:59 am

Hi Marc
I have downloaded and installed the modifications, which appear to have fixed the problem of the Weight parameter being incorrectly assigned. I can now generate a ternary plot but am having great difficulty with generating a customised legend. I have attached an XY plot showing the type of legend I would like to generate. This uses data from one or more columns in the dataset.
Na-K.jpg
Na-K.jpg (78.38 KiB) Viewed 22183 times
I have also attached a test program that uses a kbmmemtable dataset that loads csv files. What I want to do is create a legend with one line corresponding to each series.
Any help you can give me would be greatly appreciated.
Best regards
Errol
Attachments
Ternary_kbmMemTable.zip
(10.46 KiB) Downloaded 1137 times

Marc
Site Admin
Site Admin
Posts: 1272
Joined: Thu Oct 16, 2003 4:00 am
Location: Girona
Contact:

Re: Ternary Graph Assigning the Weighting parameter

Post by Marc » Mon Sep 23, 2019 8:04 am

Hello Errol,

To get the Legend to display Series names you can use the LegendStyle property:

eg.

Code: Select all

DBChart1.Legend.LegendStyle := lsSeries;
If you wish to take further control of each Legend symbol, the following event would reproduce the standard Legend (as in LegendStyle := lsSeries)

Activate the event in FormCreate:

Code: Select all

DBChart1.Legend.Symbol.OnDraw:=LegendDraw;
Then add this event procedure to the Form:

Code: Select all

//declaration
    procedure LegendDraw(Sender: TObject; Series:TChartSeries;
                         ValueIndex:Integer; R:TRect);

//implementation
procedure TTernarySeriesForm.LegendDraw(Sender: TObject; Series: TChartSeries;
  ValueIndex: Integer; R: TRect);
begin
  DBChart1.Canvas.Brush.Color := Series1.ValueColor[ValueIndex];
  if Series is TTernarySeries then
    TTernarySeries(Series).Pointer.DrawPointer(DBChart1.Canvas,false,R.Location.X+3,R.Location.Y+3,R.Width-6,R.Height-6,clTeeColor,TTernarySeries(Series).Pointer.Style)
  else //ie. if PointSeries
    TPointSeries(Series).Pointer.DrawPointer(DBChart1.Canvas,false,R.Location.X+3,R.Location.Y+3,R.Width-6,R.Height-6,clTeeColor,TPointSeries(Series).Pointer.Style);
end;
To now modify the symbols with extra content (here some lines) you can add a canvas plot lineTo.
eg.

Code: Select all

procedure TTernarySeriesForm.LegendDraw(Sender: TObject; Series: TChartSeries;
  ValueIndex: Integer; R: TRect);
begin
  DBChart1.Canvas.Brush.Color := Series1.ValueColor[ValueIndex];

  //draw line behind pointer.
  if R.Location.X <> 0 then
  Begin
  DBChart1.Canvas.MoveTo(R.Location.X-3,R.Location.Y+(R.Height div 2));
  DBChart1.Canvas.LineTo(R.Location.X+R.Width+3,R.Location.Y+(R.Height div 2));
  End;

  if Series is TTernarySeries then
    TTernarySeries(Series).Pointer.DrawPointer(DBChart1.Canvas,false,R.Location.X+4,R.Location.Y+3,R.Width-6,R.Height-6,clTeeColor,TTernarySeries(Series).Pointer.Style)
  else //ie. if PointSeries
    TPointSeries(Series).Pointer.DrawPointer(DBChart1.Canvas,false,R.Location.X+4,R.Location.Y+3,R.Width-6,R.Height-6,clTeeColor,TPointSeries(Series).Pointer.Style);
end;
If you want any Series not to be included in the Legend (the PointSeries perhaps?) then you can set the Series in this way:

Code: Select all

Series1.ShowInLegend := False;
Regards,
Marc
Steema Support

Errol
Newbie
Newbie
Posts: 29
Joined: Mon Jul 08, 2019 12:00 am

Re: Ternary Graph Assigning the Weighting parameter

Post by Errol » Fri Sep 27, 2019 12:53 am

Hi Marc
I am pleased to report that we are now able to create ternary graphs with the legend in the format we require. Thanks for all your help.
I have two further questions:

1. User-customisation of the legend position and size. I anticipate that users of our application would like to position the legend closer to the graph to save space. The legend appears to be tied to the edge of the chart - can you give an example of how to do this?

2. Do you anticipate introducing the ability to set the range on the axes? As the three axes are inter-related, if the user specifies equal ranges on two axes, the range on the other axis can be re-calculated. For instance, a sub-triangle encompassing all the data points shown in the attached diagram would have ranges as follows:
A-axis: 20 to 60 - specified by the user
B-axis: 0 to 40 - specified by the user
C-axis: 40 to 80 - automatically calculated.
This would be very useful to allow the user to "zoom" in on closely-spaced points.
Ternary_Plot2.jpg
Ternary_Plot2.jpg (125.86 KiB) Viewed 22141 times
Thanks and regards

Errol

Marc
Site Admin
Site Admin
Posts: 1272
Joined: Thu Oct 16, 2003 4:00 am
Location: Girona
Contact:

Re: Ternary Graph Assigning the Weighting parameter

Post by Marc » Fri Sep 27, 2019 8:29 am

Hello Errol,

You can custom position the Legend.

eg.

Code: Select all

  Chart1.Legend.CustomPosition := True;
  Chart1.Legend.Left := 150;
  Chart1.Legend.Top := 50;
Re. "2. Do you anticipate introducing the ability to set the range on the axes?"

There is no current plan to add Zoom to the Ternary but it can be investigated. I've added it as a feature-request and we'll look at what would need to be done. (http://bugs.teechart.net/show_bug.cgi?id=2245)

Regards,
Marc
Steema Support

Post Reply