Ternary Graph Assigning the Weighting parameter
Ternary Graph Assigning the Weighting parameter
I am having continuing problems assigning the Weighting parameter in a ternary graph, as follows:
1. If I do not assign this parameter, the graph does not draw.
2. If I assign it to the Weight field from my input memory table (derived from a csv file), the Weighting value is set to zero, and the Y field is filled with the Weight values.
3. If I assign the parameter to the same field as the Radius parameter, the Weighting is still zero, but at least the Y field is filled to the correct values.
I have attached a simple example project that shows these effects. I would be grateful if you could indicate what I am doing wrong here.
Many thanks
Errol
1. If I do not assign this parameter, the graph does not draw.
2. If I assign it to the Weight field from my input memory table (derived from a csv file), the Weighting value is set to zero, and the Y field is filled with the Weight values.
3. If I assign the parameter to the same field as the Radius parameter, the Weighting is still zero, but at least the Y field is filled to the correct values.
I have attached a simple example project that shows these effects. I would be grateful if you could indicate what I am doing wrong here.
Many thanks
Errol
- Attachments
-
- TernaryGraph_Weight.zip
- (8.82 KiB) Downloaded 1290 times
Re: Ternary Graph Assigning the Weighting parameter
As mentioned here this project seems to be using components we don't have here (TkbmMemTable, TkbmCSVStreamFormat).
If you still find problems with it, could you please arrange example projects using the minimum code to reproduce them and without using 3rd party libraries?
If you still find problems with it, could you please arrange example projects using the minimum code to reproduce them and without using 3rd party libraries?
Best Regards,
Yeray Alonso Development & Support Steema Software Av. Montilivi 33, 17003 Girona, Catalonia (SP) | |
Please read our Bug Fixing Policy |
Re: Ternary Graph Assigning the Weighting parameter
Good evening Yeray
Thank you for your response. As I use kbmMemTables with line series and bar series without any problems, I do not believe that the kbmMemTable is the cause of the difficulties I am having with Ternary Series. Rather, I feel it is because i am not correctly assigning the various axes and other ternary series parameters to the kbmMemTable fields.
Rather than rewriting the example project ot get the data from the csv file to a Ternary Series by some other method, and still failing because I am assigning the parameters incorrectly, I would appreciate it if you could write a simple example project that uses the csv file in the TernaryGraph_Weight example project as data input, and show how the X, Y, Z axes and the Radius and Weight parameters are assigned.
I look forward to receiving such a project, and appreciate all your asistance in this matter.
Best regards
Errol
Thank you for your response. As I use kbmMemTables with line series and bar series without any problems, I do not believe that the kbmMemTable is the cause of the difficulties I am having with Ternary Series. Rather, I feel it is because i am not correctly assigning the various axes and other ternary series parameters to the kbmMemTable fields.
Rather than rewriting the example project ot get the data from the csv file to a Ternary Series by some other method, and still failing because I am assigning the parameters incorrectly, I would appreciate it if you could write a simple example project that uses the csv file in the TernaryGraph_Weight example project as data input, and show how the X, Y, Z axes and the Radius and Weight parameters are assigned.
I look forward to receiving such a project, and appreciate all your asistance in this matter.
Best regards
Errol
Re: Ternary Graph Assigning the Weighting parameter
Hello Errol,
Sorry for the delay here.
Find attached the project modified to use the TSeriesTextSource instead of the kbmMemTables. It seems to work without problems:
Sorry for the delay here.
Find attached the project modified to use the TSeriesTextSource instead of the kbmMemTables. It seems to work without problems:
Best Regards,
Yeray Alonso Development & Support Steema Software Av. Montilivi 33, 17003 Girona, Catalonia (SP) | |
Please read our Bug Fixing Policy |
Re: Ternary Graph Assigning the Weighting parameter
Good afternoon
After a long break, I am back again, still trying to get ternary graphs to work.
I am writing to express my disappointment in the implementation of Ternary Graphs. We use ternary graphs to display the relationship between three data values in exactly the same way as we use regular XY graphs to display relationships between two data values. For XY graphs, we place a Chart or DBChart on a form and then send series of xy pairs to it, and have developed substantial code to handle symbols, colours, connecting lines and so on. We can easily set the axis scales to “zoom in” to show a small part of the chart in cases where there is dense data and have good control over the legend.
However, when using a ternary graph, this functionality does not seem to be available. Each series places a new ternary chart on the form, inside the previous chart, and each of which has fixed axes (0 to 100%). I understand that I can use an event to draw each chart on top of the previous chart, which is fine, but an additional complication. The legend seems to have limited functionality, and there is a Weight parameter which I still do not understand.
I would have preferred a structure more similar to a regular XY chart, that could be placed on the form and then use the equivalent of your standard line series, but requiring the definition of XValues, YValues and ZValues. If this was the case, then we could use much of our existing code to create ternary graphs. However, I presume that you have progressed too far in your development of ternary graphs to change to a form that is more compatible with regular XY graphs.
I have downloaded the TernaryGraph_Weight.zip attachment of 4 April 2019, and have got it to work - thanks. However, I do not seem to be able to alter the radius or the colours of the symbols. Also, I want to treat the data in the attached csv file as three separate series based on the name of the well, each series with a separate symbol, but with different colours for each data point. Also, I would like the option to draw a line between the data points of each series, in date order.
Any help you can give me would be greatly appreciated, or point me in the direction of the members of the TernarySeries component (i.e. the properties and methods).
I look forward to hearing from you soon.
Best regards
Errol
After a long break, I am back again, still trying to get ternary graphs to work.
I am writing to express my disappointment in the implementation of Ternary Graphs. We use ternary graphs to display the relationship between three data values in exactly the same way as we use regular XY graphs to display relationships between two data values. For XY graphs, we place a Chart or DBChart on a form and then send series of xy pairs to it, and have developed substantial code to handle symbols, colours, connecting lines and so on. We can easily set the axis scales to “zoom in” to show a small part of the chart in cases where there is dense data and have good control over the legend.
However, when using a ternary graph, this functionality does not seem to be available. Each series places a new ternary chart on the form, inside the previous chart, and each of which has fixed axes (0 to 100%). I understand that I can use an event to draw each chart on top of the previous chart, which is fine, but an additional complication. The legend seems to have limited functionality, and there is a Weight parameter which I still do not understand.
I would have preferred a structure more similar to a regular XY chart, that could be placed on the form and then use the equivalent of your standard line series, but requiring the definition of XValues, YValues and ZValues. If this was the case, then we could use much of our existing code to create ternary graphs. However, I presume that you have progressed too far in your development of ternary graphs to change to a form that is more compatible with regular XY graphs.
I have downloaded the TernaryGraph_Weight.zip attachment of 4 April 2019, and have got it to work - thanks. However, I do not seem to be able to alter the radius or the colours of the symbols. Also, I want to treat the data in the attached csv file as three separate series based on the name of the well, each series with a separate symbol, but with different colours for each data point. Also, I would like the option to draw a line between the data points of each series, in date order.
Any help you can give me would be greatly appreciated, or point me in the direction of the members of the TernarySeries component (i.e. the properties and methods).
I look forward to hearing from you soon.
Best regards
Errol
Re: Ternary Graph Assigning the Weighting parameter
Hello Errol,
If you can help us to identify and report with detail any issue you may find with it, it would help us to improve this specific series.
http://bugs.teechart.net/show_bug.cgi?id=2231
http://bugs.teechart.net/show_bug.cgi?id=2232
Welcome back!
I'm sorry to hear that. The Ternary series is a quite particular series that draws elements (like axes) in it's own way so it doesn't receive improvements and fixes made in other parts of the chart as other series do.
If you can help us to identify and report with detail any issue you may find with it, it would help us to improve this specific series.
Ok, thanks for the explanation.Errol wrote: ↑Tue Aug 27, 2019 6:16 amWe use ternary graphs to display the relationship between three data values in exactly the same way as we use regular XY graphs to display relationships between two data values. For XY graphs, we place a Chart or DBChart on a form and then send series of xy pairs to it, and have developed substantial code to handle symbols, colours, connecting lines and so on. We can easily set the axis scales to “zoom in” to show a small part of the chart in cases where there is dense data and have good control over the legend.
I've added these issues to the public tracker:Errol wrote: ↑Tue Aug 27, 2019 6:16 amHowever, when using a ternary graph, this functionality does not seem to be available. Each series places a new ternary chart on the form, inside the previous chart, and each of which has fixed axes (0 to 100%). I understand that I can use an event to draw each chart on top of the previous chart, which is fine, but an additional complication.
http://bugs.teechart.net/show_bug.cgi?id=2231
http://bugs.teechart.net/show_bug.cgi?id=2232
I'm not sure to see this limit. Could you please explain with more detail what are you missing?
The weight list is used to fill the colors of the points in range and palette styles. The point with the lowest weight is drawn with the end color in the palette, the point with the highest weight value is drawn with the start color in the palette, and the rest of points are drawn with a color calculated by extrapolation.
Indeed there are some functionalities that will be difficult to port to the Ternary series, but the majority relate to the axes. As far as I see, the rest is inherited from TCustom3DPaletteSeries which means it has the same base than other 3D series like TPoint3DSeries, TSurfaceSeries, TMapSeries,... which require XYZ.Errol wrote: ↑Tue Aug 27, 2019 6:16 amI would have preferred a structure more similar to a regular XY chart, that could be placed on the form and then use the equivalent of your standard line series, but requiring the definition of XValues, YValues and ZValues. If this was the case, then we could use much of our existing code to create ternary graphs. However, I presume that you have progressed too far in your development of ternary graphs to change to a form that is more compatible with regular XY graphs.
I'll get into this and reply you here when I'll end my tests.Errol wrote: ↑Tue Aug 27, 2019 6:16 amI have downloaded the TernaryGraph_Weight.zip attachment of 4 April 2019, and have got it to work - thanks. However, I do not seem to be able to alter the radius or the colours of the symbols. Also, I want to treat the data in the attached csv file as three separate series based on the name of the well, each series with a separate symbol, but with different colours for each data point. Also, I would like the option to draw a line between the data points of each series, in date order.
Best Regards,
Yeray Alonso Development & Support Steema Software Av. Montilivi 33, 17003 Girona, Catalonia (SP) | |
Please read our Bug Fixing Policy |
Re: Ternary Graph Assigning the Weighting parameter
Hello again,
If you set UseColorRange to false then you'll be able to individually set the colors to each point in your series.
- We could add Filters to the TSeriesTextSource (#2233)
- You could split your .csv into 3 different files
- You could load your .csv into a TFileStream, looping it and manually adding the data to each series
- You could remove the unwanted points after adding them using OnAfterAdd method (I used this approach in the attached project).
If you don't have the points sorted, you'll have to manually sort them using a temporal array.
You could use OnGetPointerStyle to use the radius with any pointer style. Ie:
Code: Select all
type TTernarySeriesAccess=class(TTernarySeries);
function TTernarySeriesForm.SeriesGetPointerStyle(Sender: TChartSeries; ValueIndex: Integer): TSeriesPointerStyle;
begin
TTernarySeriesAccess(Sender).PreparePointer(ValueIndex);
result:=TTernarySeries(Sender).Pointer.Style;
end;
The Ternary series, as the other derivates of TCustom3DPaletteSeries, uses ColorRange by default and this uses the Weight as explained my last reply above.
If you set UseColorRange to false then you'll be able to individually set the colors to each point in your series.
I can think on multiple alternatives to do this:
- We could add Filters to the TSeriesTextSource (#2233)
- You could split your .csv into 3 different files
- You could load your .csv into a TFileStream, looping it and manually adding the data to each series
- You could remove the unwanted points after adding them using OnAfterAdd method (I used this approach in the attached project).
If you have the points in your .csv already sorted, you can just loop them and draw the lines as follows:
Code: Select all
procedure TTernarySeriesForm.Chart1AfterDraw(Sender: TObject);
var i, j: Integer;
begin
for i:=0 to 2 do
with TTernarySeries(Chart1[i]) do
begin
Chart1.Canvas.MoveTo(CalcXPos(0), CalcYPos(0));
for j:=1 to Count-1 do
begin
Chart1.Canvas.LineTo(CalcXPos(j), CalcYPos(j));
end;
end;
end;
Best Regards,
Yeray Alonso Development & Support Steema Software Av. Montilivi 33, 17003 Girona, Catalonia (SP) | |
Please read our Bug Fixing Policy |
Re: Ternary Graph Assigning the Weighting parameter
Good afternoon Yeray
Thank you for your detailed reply - sorry for the delay in replying.
I am still having problems getting a ternary graph to draw. I have attached the code I use. When I run the program, selecting a single series, I just get a blank chart with a title, but without axes, vertex titles, etc.
This code works correctly if I change it to a TLineSeries instead of a TTernarySeries, so this means the data is available. Of course, I have to remove the references to ZValues, VertexTitles and UseColourRange, and change other references to TTernarySeries to TLineSeries elsewhere in the code.
I would appreciate it if you could suggest what I need to do to show the ternary chart and the data.
Thanks and regards
Errol
Thank you for your detailed reply - sorry for the delay in replying.
I am still having problems getting a ternary graph to draw. I have attached the code I use. When I run the program, selecting a single series, I just get a blank chart with a title, but without axes, vertex titles, etc.
This code works correctly if I change it to a TLineSeries instead of a TTernarySeries, so this means the data is available. Of course, I have to remove the references to ZValues, VertexTitles and UseColourRange, and change other references to TTernarySeries to TLineSeries elsewhere in the code.
I would appreciate it if you could suggest what I need to do to show the ternary chart and the data.
Thanks and regards
Errol
Code: Select all
procedure TQSCollection.InsertTernarySeries(aFieldName, aCalcField: array of string; dID: integer);
var
sTitle: string;
iIndex: integer;
begin
sTitle := self.Owner.fMultiGraphList.Strings[dID];
iIndex := 0;
if (SeriesListT.IndexOf(sTitle) = -1) then
begin
SeriesListT.AddObject(sTitle, TTernarySeries.Create(Owner));
iIndex := SeriesListT.IndexOf(sTitle);
with TTernarySeries(SeriesListT.Objects[iIndex]) as TTernarySeries do
begin
IniFile := fIniFile;
ParentChart := self.Owner.Chart;
DataSource := TDataset(self.Owner.fMultiGraphList.Objects[dID]);
Name := GetValidName(sTitle);
UseColorRange := True;
VertexTitles[0][0] := aCalcField[0];
VertexTitles[1][0] := aCalcField[1];
VertexTitles[2][0] := aCalcField[2];
YValues.ValueSource := aCalcField[0];
XValues.ValueSource := aCalcField[1];
ZValues.ValueSource := aCalcField[2];
XValues.Order := loNone;
YValues.Order := loNone;
ZValues.Order := loNone;
Pointer.Style:=psCircle;
Pointer.Transparency:=0;
Pointer.Visible := True;
ShowInLegend := False;
UseColorRange := False;
end;
end
else
DeleteSeries(SeriesListT.IndexOf(sTitle));
end;
Re: Ternary Graph Assigning the Weighting parameter
Good morning
I am still having great difficulty in producing a ternary chart by code. I have attempted to implement the various events of the Ternary Chart test program in case I am missing some important steps, but to no avail. I acknowledge that I am using components that you do not use, but I still feel that you should be able to pinpoint what I am doing wrong.
I use the following code to implement a graph using a simple line series. This works correctly, showing that the data is correctly obtained from the memory table.
The results are shown on the accompanying graphic.
However, when I change the code to use a ternary series, as shown below, I just get a blank screen. (Note: I also change other references from TLineSeries to TTernarySeries in two other places in the code, dealing with refreshing and clearing the ternary series.) I have also implemented the Chart.OnAfterDraw and Chart.OnBeforeDrawAxes events as suggested in the test program, also shown in the code. However, OnAfterDraw fails on CalcXPos(i) with a List index out of bounds(0) error.
I and my programmer have spent considerable time on this project, and I feel there is some essential information that we do not have.
Furthermore, I still do not understand why Steema did not use a simple X-Y graph with the Y-axis at a 60°angle, and with the ZValues parameter activated. 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.
To show that this approach is correct, I have attached the results of the test program. If you consider the position of the donut symbol (coordinates: Na/1000 = 30, Sqrt(Mg) = 10), this symbol would plot at exactly the same point if the Sqrt(Mg) axis ran from 0 to 100 on the bottom axis. As far as I can see, using a 3DGraph to plot ternary data is unnecessary, and a simple X-Y plot with a 60° Y-axis would suffice. I am at the end of my tether. I guess there is some simple way to get ternary graphs to work, but I haven't managed to find it.
I look forward to some guidance here.
Best regards
Errol
I am still having great difficulty in producing a ternary chart by code. I have attempted to implement the various events of the Ternary Chart test program in case I am missing some important steps, but to no avail. I acknowledge that I am using components that you do not use, but I still feel that you should be able to pinpoint what I am doing wrong.
I use the following code to implement a graph using a simple line series. This works correctly, showing that the data is correctly obtained from the memory table.
Code: Select all
procedure TQSCollection.InsertTernarySeries(aFieldName, aCalcField: array of string; dID: integer);
var
sTitle,A,B,C: string;
iIndex, iData: integer;
begin
sTitle := self.Owner.fMultiGraphList.Strings[dID];
iIndex := 0;
if (SeriesListT.IndexOf(sTitle) = -1) then
begin
SeriesListT.AddObject(sTitle, TLineSeries.Create(Owner));
iIndex := SeriesListT.IndexOf(sTitle);
with TLineSeries(SeriesListT.Objects[iIndex]) do
begin
IniFile := fIniFile;
ParentChart := self.Owner.Chart;
DataSource := TDataset(self.Owner.fMultiGraphList.Objects[dID]);
Name := GetValidName(sTitle);
YValues.ValueSource := aCalcField[0];
XValues.ValueSource := aCalcField[1];
XValues.Order := loNone;
YValues.Order := loNone;
self.Owner.Chart.Axes.Left.Automatic := True;
self.Owner.Chart.Axes.Bottom.Automatic := True;
self.Owner.Chart.Axes.Bottom.Labels := True;
self.Owner.Chart.Axes.Left.Title.Text := aCalcField[0];
self.Owner.Chart.Axes.Bottom.Title.Text := aCalcField[1];
Pointer.Style:=psCircle;
Pointer.Visible := True;
ShowInLegend := True;
self.Owner.Chart.Legend.TextStyle := ltsPlain;
self.Owner.Chart.Legend.Title.Visible:=true;
end;
end
else
DeleteSeries(SeriesListT.IndexOf(sTitle));
end;
The results are shown on the accompanying graphic.
However, when I change the code to use a ternary series, as shown below, I just get a blank screen. (Note: I also change other references from TLineSeries to TTernarySeries in two other places in the code, dealing with refreshing and clearing the ternary series.) I have also implemented the Chart.OnAfterDraw and Chart.OnBeforeDrawAxes events as suggested in the test program, also shown in the code. However, OnAfterDraw fails on CalcXPos(i) with a List index out of bounds(0) error.
Code: Select all
procedure TQSCollection.InsertTernarySeries(aFieldName, aCalcField: array of string; dID: integer);
var
sTitle,A,B,C: string;
iIndex, iData: integer;
T: TTernarySeries;
begin
sTitle := self.Owner.fMultiGraphList.Strings[dID];
iIndex := 0;
T := TTernarySeries(self.Owner.Chart.AddSeries(TTernarySeries));
if (SeriesListT.IndexOf(sTitle) = -1) then
begin
SeriesListT.AddObject(sTitle, T);
iIndex := SeriesListT.IndexOf(sTitle);
with T as TTernarySeries do
begin
IniFile := fIniFile;
ParentChart := self.Owner.Chart;
DataSource := TDataset(self.Owner.fMultiGraphList.Objects[dID]);
Name := GetValidName(sTitle);
if dID > 0 then
begin
VertexTitle.Hide;
self.Owner.Chart.Axes.Hide;
BeforeDrawValues:=BeforeDrawSecond;
end
else
begin
self.Owner.Chart.Visible := True;
self.Owner.chart.Axes.Visible:=True;
BeforeDrawValues:=BeforeDrawFirst;
end;
OnAfterAdd := SeriesAfterAdd;
UseColorRange := True;
VertexTitles[0][0] := aCalcField[0];
VertexTitles[1][0] := aCalcField[1];
VertexTitles[2][0] := aCalcField[2];
XValues.ValueSource := aCalcField[0];
YValues.ValueSource := aCalcField[1];
ZValues.ValueSource := aCalcField[2];
XValues.Order := loNone;
YValues.Order := loNone;
ZValues.Order := loNone;
Active := True;
Pointer.Style:=psCircle;
Pointer.Transparency:=0;
Pointer.Visible := True;
ShowInLegend := False;
UseColorRange := False;
self.Owner.Chart.Legend.TextStyle := ltsPlain;
self.Owner.Chart.Legend.Title.TextAlignment := taLeftJustify;
self.Owner.Chart.Legend.Width :=100;
self.Owner.Chart.Legend.Title.Visible:=true;
self.Owner.Chart.Walls.Back.Hide;
end;
end
else
DeleteSeries(SeriesListT.IndexOf(sTitle));
end;
procedure TPBQuickGraph.SetupTernaryChart(AIndex: integer);
begin
Chart.OnAfterDraw := TernaryChartAfterDraw;
Chart.OnBeforeDrawAxes := TernaryChartBeforeDrawAxes;
fTernaryCollection.ClearAllTernarySeries;
end;
procedure TPBQuickGraph.TernaryChartAfterDraw(Sender: TObject);
var i, j: Integer;
begin
for i:=0 to fMultiGraphlist.Count - 1 do
with TTernarySeries(Chart[i]) do
begin
Chart.Canvas.MoveTo(CalcXPos(i), CalcYPos(i));
for j:=1 to Count-1 do
begin
Chart.Canvas.LineTo(CalcXPos(j), CalcYPos(j));
end;
end;
end;
Furthermore, I still do not understand why Steema did not use a simple X-Y graph with the Y-axis at a 60°angle, and with the ZValues parameter activated. 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.
To show that this approach is correct, I have attached the results of the test program. If you consider the position of the donut symbol (coordinates: Na/1000 = 30, Sqrt(Mg) = 10), this symbol would plot at exactly the same point if the Sqrt(Mg) axis ran from 0 to 100 on the bottom axis. As far as I can see, using a 3DGraph to plot ternary data is unnecessary, and a simple X-Y plot with a 60° Y-axis would suffice. I am at the end of my tether. I guess there is some simple way to get ternary graphs to work, but I haven't managed to find it.
I look forward to some guidance here.
Best regards
Errol
Re: Ternary Graph Assigning the Weighting parameter
Hello Errol,
The way the Ternary Series was devised was to use 5 components:
X,Y,Z values and Radius and Weight.
X,Y and Z position the point as a measure of proportionality of each of the three values. Radius decides the visible radius of the point and Weight uses a colour scale.
This code then plots four points, one equidistant from each axis (centered) and the other offset proportionally as per their values:
output:
TernarySeries won't share the chart with other series types so they need to be Active:=False;
Your code sample has a degree of complexity in which I don't clearly see yet where the obstacle might be but I can try and mimic some of the steps to populate the Series to see if it becomes clearer to me where the problem may lie.
Regards,
Marc Meumann
The way the Ternary Series was devised was to use 5 components:
X,Y,Z values and Radius and Weight.
X,Y and Z position the point as a measure of proportionality of each of the three values. Radius decides the visible radius of the point and Weight uses a colour scale.
This code then plots four points, one equidistant from each axis (centered) and the other offset proportionally as per their values:
Code: Select all
procedure TForm13.Button1Click(Sender: TObject);
begin
Series1.AddBubbleXYZWeight(10,10,10,5,1,clTeeColor);
Series1.AddBubbleXYZWeight(30,20,10,15,2,clTeeColor);
Series1.AddBubbleXYZWeight(20,10,30,25,3,clTeeColor);
Series1.AddBubbleXYZWeight(10,30,20,35,4,clTeeColor);
Series1.UsePalette := True;
Series1.TernaryStyle := tsBubble;
Series1.Marks.Style := smsPointIndex;
end;
Your code sample has a degree of complexity in which I don't clearly see yet where the obstacle might be but I can try and mimic some of the steps to populate the Series to see if it becomes clearer to me where the problem may lie.
Regards,
Marc Meumann
Steema Support
Re: Ternary Graph Assigning the Weighting parameter
As a footnote on this, looking more closely at your comments, as I see that the goal is to make the Ternary plot from two variables, there may be a possibility of adding an overload to facilitate that. We'll take a look.
Regards,
Marc
Regards,
Marc
Re: Ternary Graph Assigning the Weighting parameter
Hello Errol,
Re.
TeeChart's Ternary is based on a 3 value plot:
https://en.wikipedia.org/wiki/Ternary_p ... rnary_plot
Re.
Please note:
The plot you describe seems somewhat different, common only perhaps, in having 60º axes. If there is a standard that defines the % of A and B without C then we'll need to know it and can work with it.
Re.
With thanks.
Regards,
Marc
Re.
Furthermore, I still do not understand why Steema did not use a simple X-Y graph with the Y-axis at a 60°angle, and with the ZValues parameter activated.
TeeChart's Ternary is based on a 3 value plot:
https://en.wikipedia.org/wiki/Ternary_p ... rnary_plot
Re.
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.
Please note:
(where k is 1.0 or 100%)c must be equal to K − a − b
The plot you describe seems somewhat different, common only perhaps, in having 60º axes. If there is a standard that defines the % of A and B without C then we'll need to know it and can work with it.
Re.
Once we have the definition we'll be happy to have a go. Do you have any examples/references we can use? We assume that the third variable is not relevant and what you're interested in is the % relationship between A and B (X and Y).This is the approach of most scientific graphing applications.
With thanks.
Regards,
Marc
Steema Support
Re: Ternary Graph Assigning the Weighting parameter
Hi Marc
Thank you for your reply. A ternary graph requires three values to calculate relative percentages, but only two values need to be plotted on a ternary graph as the third value is automatically 100 - A - B (working in percentages) as you state. If you use a regular XY chart with with the Y value at 60°and fixed ranges of 0 to 100 on each axis, and plot A on the Y axis on a line parallel with the X-axis and B on the X-axis on a line parallel with the y-axis, then the point is in exactly the same position as you obtain in your formulation.
Early work by Giggenbach, a geochemist in the geothermal industry, used this technique. If you search for "Giggenbach ternary diagrams", you will see many images, some with Mg plotted on the bottom axis going from left to right, and others with Mg on the right axis going from top to bottom. The positions of the points in either format are identical - the 10% line can either be projected from the bottom axis at a 6o° angle or from the right axis at -60°. (Note that Giggenbach used the regular X-Y plot initially as the graphing tools he had available had the option to draw the y-axis at an angle other than 90°).
Therefore, a ternary graph formulation using regular line, point and fastline series but with a 60° Y-axis and with a special A-B-C axis format, would be much more compatible with regular graphing used elsewhere.
However, I have another question. In the test program (TernaryGraph_Weight.zip) provided earlier in this thread, the code is shown below. In this code, I do not understand how Chart1[ i ] is created. When I try to emulate this code, I cannot create an "apparent" array of charts, which I presume is why I am not getting any output.
I look forward to your comments.
Best regards
Errol
Thank you for your reply. A ternary graph requires three values to calculate relative percentages, but only two values need to be plotted on a ternary graph as the third value is automatically 100 - A - B (working in percentages) as you state. If you use a regular XY chart with with the Y value at 60°and fixed ranges of 0 to 100 on each axis, and plot A on the Y axis on a line parallel with the X-axis and B on the X-axis on a line parallel with the y-axis, then the point is in exactly the same position as you obtain in your formulation.
Early work by Giggenbach, a geochemist in the geothermal industry, used this technique. If you search for "Giggenbach ternary diagrams", you will see many images, some with Mg plotted on the bottom axis going from left to right, and others with Mg on the right axis going from top to bottom. The positions of the points in either format are identical - the 10% line can either be projected from the bottom axis at a 6o° angle or from the right axis at -60°. (Note that Giggenbach used the regular X-Y plot initially as the graphing tools he had available had the option to draw the y-axis at an angle other than 90°).
Therefore, a ternary graph formulation using regular line, point and fastline series but with a 60° Y-axis and with a special A-B-C axis format, would be much more compatible with regular graphing used elsewhere.
However, I have another question. In the test program (TernaryGraph_Weight.zip) provided earlier in this thread, the code is shown below. In this code, I do not understand how Chart1[ i ] is created. When I try to emulate this code, I cannot create an "apparent" array of charts, which I presume is why I am not getting any output.
I look forward to your comments.
Best regards
Errol
Code: Select all
procedure TTernarySeriesForm.FormCreate(Sender: TObject);
var
i: integer;
begin
inherited;
FormatSettings.DecimalSeparator:='.';
for i:=0 to 2 do
begin
with TTernarySeries(Chart1.AddSeries(TTernarySeries)) do
begin
case i of
0: begin
Title:='AT-303';
Pointer.Style:=psDonut;
end;
1: begin
Title:='AT-505';
Pointer.Style:=psTriangle;
end;
2: begin
Title:='AT-602';
Pointer.Style:=psDownTriangle;
end;
end;
if i>0 then
begin
VertexTitle.Hide;
Chart1.Axes.Hide;
BeforeDrawValues:=BeforeDrawSecond;
end
else
BeforeDrawValues:=BeforeDrawFirst;
OnAfterAdd:=SeriesAfterAdd;
DataSource := SeriesTextSource1;
with SeriesTextSource1 do
begin
HeaderLines:=1;
FileName := 'Na-Mg-K.csv';
FieldSeparator:=',';
Fields.Clear;
AddField('X',3);
AddField('Y',4);
AddField('Z',5);
AddField('Radius',6);
AddField('Weighting',7);
AddField('Text',8);
Load;
end;
UseColorRange:=true;
VertexTitles[0][0] := 'Na/1000' ;
VertexTitles[1][0] := 'Sqrt(Mg)' ;
VertexTitles[2][0] := 'K/100' ;
Pointer.Transparency:=50;
ShowInLegend:=False;
UseColorRange:=False;
OnGetPointerStyle:=SeriesGetPointerStyle;
end;
end;
for i:=0 to 2 do
begin
with TPointSeries(Chart1.AddSeries(TPointSeries)) do
begin
Title:=Chart1[i].Title;
Pointer.Style:=TTernarySeries(Chart1[i]).Pointer.Style;
end;
end;
Chart1.Legend.Title.TextAlignment := taLeftJustify;
Chart1.Legend.Width :=30;
Chart1.Legend.Title.Visible:=true;
Chart1.Walls.Back.Hide;
end;
Re: Ternary Graph Assigning the Weighting parameter
Hello Errol,
Re.
I put in a temporary fix for your project which generates the Chart image attached. Notice that Ternary points have moved respectively. We'll revise how best to apply this fix for inclusion with the next release update.
That doesn't answer your question though.
Your test project loads via SeriesTextSource to several Series. Have you considered loading this as one Series?
eg. ... you can still use the SeriesTextSource instead of the i loop.
There'd be a slight extra setting the Legend pointers and max Legend rows, I'll see if a get a moment to build a small example (based on TeeChart featuredemo:"Legend:Symbol OnDraw").
We'll look at Giggenbach, thanks.
Regards,
Marc
Re.
Firstly, your project has highlighted a bug between SeriesTextSrc and the Ternary Series. I noticed it when looking at the Y values reported in the data section of the Editor. Y is coming up as the Weighting value. That's because (the bug) SeriesTextSrc uses what's called the MandatoryValueList for its second value. For most Series Types Y is mandatory (ie a chart could be created with x as a sequential index but Y needs to have some significance). For the case of Ternary X,Y,Z are all treated as equals and it's Weight that shows the true value difference and that was chosen to be Mandatory. That's being erroneously picked up by SeriesTextSource.However, I have another question. In the test program (TernaryGraph_Weight.zip) provided earlier in this thread, the code is shown below. In this code, I do not understand how Chart1[ i ] is created. When I try to emulate this code, I cannot create an "apparent" array of charts, which I presume is why I am not getting any output.
I put in a temporary fix for your project which generates the Chart image attached. Notice that Ternary points have moved respectively. We'll revise how best to apply this fix for inclusion with the next release update.
That doesn't answer your question though.
Your test project loads via SeriesTextSource to several Series. Have you considered loading this as one Series?
eg. ... you can still use the SeriesTextSource instead of the i loop.
Code: Select all
procedure TForm12.Button1Click(Sender: TObject);
function GetLabel(Idx : Integer) : String;
Begin
if idx <2 then
result:='1st'
else if idx < 4 then
result:='2nd'
else result:='3rd';
End;
begin
Series1.Clear;
for i:=0 to 5 do
Begin
//some random data
Series1.AddBubbleXYZWeight(Random(30),Random(20),Random(10),4 + Random(4),i,clTeeColor);
Series1.Labels[Series1.Count-1] := GetLabel(Series1.Count-1);
End;
Series1.UsePalette := True;
Series1.TernaryStyle := tsBubble;
Series1.Marks.Style := smsPointIndex;
Chart1.Legend.MaxNumRows := Chart1.SeriesCount;
Chart1.Legend.LegendStyle := lsValues;
end;
function TForm12.Series1GetPointerStyle(Sender: TChartSeries;
ValueIndex: Integer): TSeriesPointerStyle;
begin
//some code to control pointer type
if ValueIndex <2 then
result:=psDonut
else if ValueIndex < 4 then
result:=psTriangle
else result:=psDownTriangle;
end;
We'll look at Giggenbach, thanks.
Regards,
Marc
Steema Support
Re: Ternary Graph Assigning the Weighting parameter
Hello Errol,
Taking up your lead; to simplify things a little we're internalising code to enable multiple Ternary Series in one Chart without the need for custom code in the form.
Regards,
Marc
Taking up your lead; to simplify things a little we're internalising code to enable multiple Ternary Series in one Chart without the need for custom code in the form.
Regards,
Marc
Steema Support