### Bookstore

 Computer Math and Games in Pascal (preview) Lazarus Handbook

### Author Topic: Chart with two separate vertical axis and linear transformation  (Read 732 times)

#### AmirNA

• New member
• Posts: 9
##### Chart with two separate vertical axis and linear transformation
« on: August 22, 2022, 07:23:06 am »
I have simple code with a chart and two series.
First one is random number between 0 and 25 (C) which is assigned to left axis.
The second one is random number between -4 and 32 (in Fahrenheit) and is assigned to the right axis.
I want to have linear transformation for the right axis to show the values in Kelvin. Therefore, range for the right axis should be from 253 to 273. But the linear transformation is not working and values are still in Fahrenheit

I appreciate if someone could help me with this.

By the way both axis’s have auto transformation.

#### wp

• Hero Member
• Posts: 10266
##### Re: Chart with two separate vertical axis and linear transformation
« Reply #1 on: August 22, 2022, 12:31:00 pm »
I think you are using the axistransformations for something they were not designed for.

Just for explanation let's assume that you want a log presentation of your data, say: in the range between 1 and 1000. This means: your data in their "own" units, or "axis" units in TAChart speak, are in the range between 1 and 1000. The log axis transformation calculates the log and creates values in "graph" units which are the logs of the "axis" units. The chart plots graph units. These are numbers in the range between log(1)=1 and log(1000)=3. But you don't want "graph" units on the axis - you want the real data units, i.e. the "axis" units. Therefore, for labeling the axis, the chart calculates the inverse transformation of the transformed values (i.e. it calculates the exponential of the log values) to return the numbers back into axis units. Therefore, the chart can plot the numbers in log units (1..3), but labels the axis in the real units (1..1000).

Your request is different: you want to transform the input values (Fahrenheit) to Kelvin by means of the LinearAxisTransform, but you want to label the axis in K too. However, since the chart performs the inverse transformation for the axis labels, you end up with the Fahrenheit numbers on the axis again...

Normally you can "fix" this when you do not link the series to the axis, i.e. return AxisIndexY to -1, but keep the LinearAxisTransform attached to the axis. This way the chart plots the original values (Fahrenheit), but the axis is labeled in Kelvin... A bit counter-intuitive, I know... I am attaching the modified project as "1-series.zip".

This does not work for you in your case since you do need the transformation linked to the series because you want to auto-scale both series. So, you cannot use your approach. Sorry.

But why don't you convert the numbers to K before you add them to the series?

Ideally, I think, there should be some kind of "TransformedChartSource" which does some calculation with the data values before they are passed on to the chart. Maybe I should write something like this...

On the other hand, it is already there: the TUserDefinedChartSource. Link the series to the UserDefinedChartSource and pass your data through it by means of the OnGetChartDataItem event where you immediately can perform the transformation. See attached modified demo.
Code: Pascal  [Select][+][-]
1. function FahrenheitToKelvin(F: Double): Double;
2. begin
3.   Result := (F - 32) / 1.8 + 273.15;
4. end;
5.
6. // The user-defined chart source is named "ucdTWinter" here...
7. procedure TForm1.ucsTWinterGetChartDataItem(ASource: TUserDefinedChartSource;
8.   AIndex: Integer; var AItem: TChartDataItem);
9. begin
10.   // rcsTWinter is the chart source which stores the original data
11.   AItem.X := rcsTWinter.Item[AIndex]^.X;
12.   AItem.Y := FahrenheitToKelvin(rcsTWinter.Item[AIndex]^.Y);
13. end;
14.
15. procedure TForm1.FormCreate(Sender: TObject);
16. begin
17.   // Link the user-defined chartsource to the series
18.   ChartTWinterLine.Source := ucsTWinter;
19.   // Setting the points number makes the user-defined series usable.
20.   ucsTWinter.PointsNumber := rcsTWinter.Count;
21. end;

#### AmirNA

• New member
• Posts: 9
##### Re: Chart with two separate vertical axis and linear transformation
« Reply #2 on: August 23, 2022, 12:44:22 am »

Thanks for the explanation and codes.

The code that I put here was just an example. In my real code I keep all of the data in SI units and most of the times I have to show the result with more than one unit. Therefore, I use linear transformation to show the result for those units (such as C, F, K). With one type of dimension everything works fine. But when I have two or more different dimensions for example length and volume together, then the code does not work.

#### AmirNA

• New member
• Posts: 9
##### Re: Chart with two separate vertical axis and linear transformation
« Reply #3 on: August 23, 2022, 01:21:46 am »
Based on your comment, I found a simple solution for it. I just need to change the marks on the axis and not the actual values.
Thanks a lot.

procedure TForm1.ChartTAxisList2GetMarkText(Sender: TObject; var AText: String;
AMark: Double);
begin
Atext := FloatToStr(AMark * 1.8 - 459.67);
end;

procedure TForm1.ChartTAxisList2MarkToText(var AText: String; AMark: Double);
begin
Atext := FloatToStr((AMark - 32) / 1.8 + 273.15);
end;

#### PascalDragon

• Hero Member
• Posts: 4744
• Compiler Developer
##### Re: Chart with two separate vertical axis and linear transformation
« Reply #4 on: August 23, 2022, 09:21:23 am »
procedure TForm1.ChartTAxisList2GetMarkText(Sender: TObject; var AText: String;
AMark: Double);
begin
Atext := FloatToStr(AMark * 1.8 - 459.67);
end;

procedure TForm1.ChartTAxisList2MarkToText(var AText: String; AMark: Double);
begin
Atext := FloatToStr((AMark - 32) / 1.8 + 273.15);
end;

Please use [ code ]-tags. Thank you.

#### wp

• Hero Member
• Posts: 10266
##### Re: Chart with two separate vertical axis and linear transformation
« Reply #5 on: August 23, 2022, 10:56:33 am »
I just need to change the marks on the axis and not the actual values.
While this looks simple at first sight it has the disadvantage that this event is fired after the label positions already have been calculated. Therefore, the labels are drawn at the positions determined on the basis of the original data units, but not on the basis of the new units. Have a look at the attached demo "OnGetMarkText" which uses the OnGetMarkText to convert labels of the temperature axis between Celsius, Fahrenheit and Kelvin. The raw data are in Celsius. Therefore, the temperature axis is labeled nicely for Celsius. When units are switched labels are drawn at the same positions. For the Fahrenheit scale, in particular, this results in strange labels because the integer values are not labelled any more. (I do remember that 16C = 16F, therefore I'd expect to see the 16F label, but the 16F label is not drawn at all).

I still would prefer to convert data before they go into the chart. If you do not want to modify the original values, store them in an array and use a UserDefinedChartSource to pass them to the series. Write an OnGetChartDataItem handler for the chart source to tell the series how to get the plot data. You can apply the conversion here easily without modifying the original data values. As a consequence, the chart only sees data in the new units, and thus performs axis labelling on the basis of the new units. See sample project "UserDefinedChartSource" (Here the 16C = 16F fixpoint is nicely seen).

#### AmirNA

• New member
• Posts: 9
##### Re: Chart with two separate vertical axis and linear transformation
« Reply #6 on: August 24, 2022, 11:37:37 pm »
I agree it is not the best answer and the result will not be as nice as yours.
when we have separates vertical (or horizontal) axis's, is there any way to assign secondary axis to one of them?

#### AmirNA

• New member
• Posts: 9
##### Re: Chart with two separate vertical axis and linear transformation
« Reply #7 on: August 24, 2022, 11:38:54 pm »
For example add another axis's to show winter temperature in other unit?

#### wp

• Hero Member
• Posts: 10266
##### Re: Chart with two separate vertical axis and linear transformation
« Reply #8 on: August 25, 2022, 12:05:12 am »
For example add another axis's to show winter temperature in other unit?
Sorry, I don't understand... You want a second axis at the right to display winter temperature in different units than the current right axis?

#### AmirNA

• New member
• Posts: 9
##### Re: Chart with two separate vertical axis and linear transformation
« Reply #9 on: August 25, 2022, 12:11:00 am »
Yes, I want to show the winter data with two different units. For example F and C at the same time. The problem is the series is link to one axis. How can I relate the second axis to this one?

#### wp

• Hero Member
• Posts: 10266
##### Re: Chart with two separate vertical axis and linear transformation
« Reply #10 on: August 25, 2022, 01:01:29 am »
Since you plot the original data (which are in Fahrenheit) and only use the onGetMarkText event to convert the unit you do not need the fahrenheit-to-Kelvin AxisTransformation any more. Delete it, it makes life much easier. What's left is the AutoScaleTransformation for the left axis and the right axis. This is needed to expand the sommer and winter temperatures over the full plotting scale.

OK. Now add a third axis, and make it a right axis. Simply assign the winter temperature transformation (catT) to this axis - it is now used by both right axes. Since this transformation is attached to the winter temperature series the new axis gets the same labels as the first right axis. Without your OnGetMarkText handler both axes would display the same labels. But since one of the right axes has the selected conversion in its OnGetMarkText handler it displays the labels in the selected units while the other axis has labels in the data units, which are Fahrenheit. Of course you can even add a separate onGetMarkText handler to the new right axis and allow the user unit selection here as well.

In the attachment you find your demo extended by a second right axis which always displays Fahrenheit.

#### AmirNA

• New member
• Posts: 9
##### Re: Chart with two separate vertical axis and linear transformation
« Reply #11 on: August 25, 2022, 11:30:58 pm »
Thanks a lot.