Recent

Author Topic: Correct display of values in logarithmic scales in TAChart  (Read 6496 times)

maurobio

  • Hero Member
  • *****
  • Posts: 623
  • Ecology is everything.
    • GitHub
Correct display of values in logarithmic scales in TAChart
« on: June 30, 2017, 03:25:40 pm »
Dear ALL,

I have been playing with TAChart for the creation of word frequency plots, with log scales in both axes.

I would like to create something like the image in the attached "Results.png" file, but I have a hard time with the correct display of the series axes (see the attached "project1.png").

My simple question is how could I correctly configure and format the display of values in scientific notation in a TAChart object using log-transformed axes.

(Please notice that I have been playing only with the y-axis, so the x-axis is still messy).

Here is my code so far (EDIT: the whole project files are in the attached zip archive):

Code: Pascal  [Select][+][-]
  1. program project1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   {$IFDEF UNIX}{$IFDEF UseCThreads}
  7.   cthreads,
  8.   {$ENDIF}{$ENDIF}
  9.   Interfaces, // this includes the LCL widgetset
  10.   Forms, Unit1, tachartlazaruspkg
  11.   { you can add units after this };
  12.  
  13. {$R *.res}
  14.  
  15. begin
  16.   RequireDerivedFormResource:=True;
  17.   Application.Initialize;
  18.   Application.CreateForm(TForm1, Form1);
  19.   Application.Run;
  20. end.
  21.  
  22. unit Unit1;
  23.  
  24. {$mode objfpc}{$H+}
  25.  
  26. interface
  27.  
  28. uses
  29.   Classes, SysUtils, FileUtil, TAGraph, TASeries, TATransformations, Forms,
  30.   Controls, Graphics, Dialogs, Math;
  31.  
  32. type
  33.  
  34.   { TForm1 }
  35.  
  36.   TForm1 = class(TForm)
  37.     Chart1: TChart;
  38.     ChartAxisTransformations1: TChartAxisTransformations;
  39.     ChartAxisTransformations1LogarithmAxisTransform1: TLogarithmAxisTransform;
  40.     Series1: TLineSeries;
  41.     procedure FormCreate(Sender: TObject);
  42.     procedure FormDestroy(Sender: TObject);
  43.   private
  44.     { private declarations }
  45.   public
  46.     { public declarations }
  47.   end;
  48.  
  49. var
  50.   Form1: TForm1;
  51.  
  52. implementation
  53.  
  54. {$R *.lfm}
  55.  
  56. { TForm1 }
  57.  
  58. procedure TForm1.FormCreate(Sender: TObject);
  59. var
  60.    I: Integer;
  61.    Frequency: array[1..12] of Integer;
  62. begin
  63.   for I := 1 to 12 do
  64.       Frequency[I] := 1;
  65.   Frequency[1] := 2;
  66.   for I := 1 to 12 do begin
  67.       //Series1.AddXY(Log2(I), Log2(Frequency[I]));
  68.       Series1.AddXY(I, Frequency[I]);
  69.   end;
  70. end;
  71.  
  72. procedure TForm1.FormDestroy(Sender: TObject);
  73. begin
  74.   Chart1.SaveToFile(TPortableNetworkGraphic, 'project1.png');
  75. end;
  76.  
  77. end.
  78.  
  79. object Form1: TForm1
  80.   Left = 237
  81.   Height = 398
  82.   Top = 120
  83.   Width = 775
  84.   Caption = 'Form1'
  85.   ClientHeight = 398
  86.   ClientWidth = 775
  87.   OnCreate = FormCreate
  88.   OnDestroy = FormDestroy
  89.   LCLVersion = '1.6.0.4'
  90.   object Chart1: TChart
  91.     Left = 0
  92.     Height = 398
  93.     Top = 0
  94.     Width = 775
  95.     AxisList = <    
  96.       item
  97.         Grid.Visible = False
  98.         Intervals.Count = 2
  99.         Intervals.Tolerance = 100
  100.         Marks.Format = '%0.0e'
  101.         Marks.Style = smsCustom
  102.         Minors = <>
  103.         Title.LabelFont.Height = -13
  104.         Title.LabelFont.Orientation = 900
  105.         Title.Visible = True
  106.         Title.Caption = 'frequency (log)'
  107.         Transformations = ChartAxisTransformations1
  108.       end    
  109.       item
  110.         Grid.Visible = False
  111.         Alignment = calBottom
  112.         Marks.Format = '%0.0e'
  113.         Marks.Style = smsCustom
  114.         Minors = <>
  115.         Title.LabelFont.Height = -13
  116.         Title.Visible = True
  117.         Title.Caption = 'rank (log)'
  118.         Transformations = ChartAxisTransformations1
  119.       end>
  120.     BackColor = clWhite
  121.     Foot.Brush.Color = clBtnFace
  122.     Foot.Font.Color = clBlue
  123.     Title.Brush.Color = clBtnFace
  124.     Title.Font.Color = clBlack
  125.     Title.Font.Height = -16
  126.     Title.Font.Style = [fsBold]
  127.     Title.Text.Strings = (
  128.       'Plot of word frequency'
  129.     )
  130.     Title.Visible = True
  131.     Align = alClient
  132.     Color = clWhite
  133.     object Series1: TLineSeries
  134.       LinePen.Color = clTeal
  135.       LinePen.Width = 2
  136.       Pointer.Brush.Color = clTeal
  137.       Pointer.Pen.Color = clTeal
  138.       Pointer.Style = psCircle
  139.       ShowPoints = True
  140.     end
  141.   end
  142.   object ChartAxisTransformations1: TChartAxisTransformations
  143.     left = 200
  144.     top = 8
  145.     object ChartAxisTransformations1LogarithmAxisTransform1: TLogarithmAxisTransform
  146.       Base = 10
  147.     end
  148.   end
  149. end

Thanks in advance for any assistance you can provide!

With warmest regards,
« Last Edit: June 30, 2017, 03:49:31 pm by maurobio »
UCSD Pascal / Burroughs 6700 / Master Control Program
Delphi 7.0 Personal Edition
Lazarus 2.0.12 - FPC 3.2.0 on GNU/Linux Mint 19.1, Lubuntu 18.04, Windows XP SP3, Windows 7 Professional, Windows 10 Home

wp

  • Hero Member
  • *****
  • Posts: 11853
Re: Correct display of values in logarithmic scales in TAChart
« Reply #1 on: June 30, 2017, 05:23:07 pm »
First of all: your data cover only a small range. Is it absolutely necessary to fight against the issues of log axes here, wouldn't linear axes be sufficient?

With "scientific notation" you mean displaying the label 2E1 as "2 x 101"? This is not possible - at least at the moment. But you are lucky: At the moment I am working at a way how to embed HTML tags into axis labels and titles. When this is finished, there will be either an automatic way (maybe a property "ScientificExponent") or at least the event OnMarkToText of the axis where you should implement something like:
Code: Text  [Select][+][-]
  1. procedure TForm1.Chart1AxisList1MarkToText(var AText: String; AMark: Double);
  2. var
  3.   s: String;
  4.   ex: Integer;
  5. begin
  6.   s := Format(Chart1.LeftAxis.Format, [AMark]);
  7.   ex := StrToInt(Copy(AText, pos('E', AText) + 1));
  8.   AText := Copy(AText, 1, pos('E', AText)-1) + ' &times; 10<sup>' + IntToStr(ex) + '</sub>';
  9. end;
But wait until it's finished...

I saw some issues in your sample project:
  • If you work with Axistransformations you always must assign the index of the axis which is affected by the transformation to the AxisIndexX or AxisIndexY of the series. Otherwise the series cannot perform the transformation because it does not "know" it.
  • For the x axis you'll need a separate ChartAxisTransformations component.
  • The best set of "Interval" parameters for a log axis is:
    - add aipGraphCoords to Options
    - use a small, non-zero Tolerance value, e.g. 5.
    - increase the MaxLength and MinLength, in particular if you use exponential formatting (%.0e) which results in long labels
  • Still - the log axis labels will probably not look the way you want them. If you have specific requirements it usually is the best to add the allowed label values to a ListChartSource and assign it to the Marks.Source of the axis.

maurobio

  • Hero Member
  • *****
  • Posts: 623
  • Ecology is everything.
    • GitHub
Re: Correct display of values in logarithmic scales in TAChart
« Reply #2 on: June 30, 2017, 05:54:12 pm »
Dear wp,

Thanks for your fast reply. Indeed, with your directions and suggestions I managed to get an acceptable plot (see the attached image). My only issue is with numbers appearing repeated times on the y-axis! Why should this happen (and how to fix it)?

I gave up the use of exponential notation for the time being. Will wait for your improvements which will allow the rendering of "true" scientific notation on the plot axes.

As of the small size of my test dataset, please notice that this is a just very restricted example - my real text analysis application will handle thousands of words (indeed, entire books).

Again, thank you very much for your great help!

Warmest regards,
UCSD Pascal / Burroughs 6700 / Master Control Program
Delphi 7.0 Personal Edition
Lazarus 2.0.12 - FPC 3.2.0 on GNU/Linux Mint 19.1, Lubuntu 18.04, Windows XP SP3, Windows 7 Professional, Windows 10 Home

wp

  • Hero Member
  • *****
  • Posts: 11853
Re: Correct display of values in logarithmic scales in TAChart
« Reply #3 on: June 30, 2017, 06:51:18 pm »
The single-digit left axis labels probably are due to the Marks.Format specified. In the demo you had used "%0.0e" for the logarithmic axis, on the linear axis you probably have "%0.0f". Note that the number after the decimal point is the number of decimal places. So, "%0.0f" means: no decimal places! Use "%0.1f" instead, or "%0.1f". Or return to the default "%.9g": Use up to 9 decimal places if required, or less ("%.9f" would mean: "Always use 9 decimal places").

How many orders of magnitude are spanned by your data both on x and on y? I could work out an example with user-defined chartsources which would have labels always and only at 1, 10, 100 etc.

maurobio

  • Hero Member
  • *****
  • Posts: 623
  • Ecology is everything.
    • GitHub
Re: Correct display of values in logarithmic scales in TAChart
« Reply #4 on: June 30, 2017, 09:19:55 pm »
Dear wp,

Thanks again for your help! Sure, I forgot to change the formatting strings in the y-axis. Using '%.2f" results in an acceptable plot.

Attached is a plot (created in Python with the Matplotlib library) which provides a typical exemple of the of kind of data I am expected to analyze with my application (in that case, the full text of "The Hound of the Baskervilles" by Conan Doyle). It would be really great if the plots could have only integer labels on a decimal scale, as you suggested. Any help in this regard will be much appreciated! :D

Warmest regards,
UCSD Pascal / Burroughs 6700 / Master Control Program
Delphi 7.0 Personal Edition
Lazarus 2.0.12 - FPC 3.2.0 on GNU/Linux Mint 19.1, Lubuntu 18.04, Windows XP SP3, Windows 7 Professional, Windows 10 Home

wp

  • Hero Member
  • *****
  • Posts: 11853
Re: Correct display of values in logarithmic scales in TAChart
« Reply #5 on: June 30, 2017, 11:44:11 pm »
Here is the promised sample project. It creates some dummy data similar to yours and populates two ChartListSources with the power-of-10 values for the x and y data intervals. In this procedure the label texts are assigned to each label coordinates a bit differently from the default - I thought that something like 10^2 might come closer to your requirement than the default 1E-02.

You may notice that there is also a minor grid. Look at the tutorial http://wiki.lazarus.freepascal.org/TAChart_Tutorial:_ListChartSource,_Logarithmic_Axis,_Fitting how to get this done.

Also, look at the source code of the demo, it contains more comments explaining some details.


maurobio

  • Hero Member
  • *****
  • Posts: 623
  • Ecology is everything.
    • GitHub
Re: Correct display of values in logarithmic scales in TAChart
« Reply #6 on: July 01, 2017, 12:12:41 am »
Dear wp,

This is absolutely superb and perfect!!! Thank you very much indeed for taking the time to help me. I can only retribute by stating that my application will be open source and absolutely free for all (and hopefully cross-platform).

Long live to Free Pascal/Lazarus!  :D

With warmest regards,
UCSD Pascal / Burroughs 6700 / Master Control Program
Delphi 7.0 Personal Edition
Lazarus 2.0.12 - FPC 3.2.0 on GNU/Linux Mint 19.1, Lubuntu 18.04, Windows XP SP3, Windows 7 Professional, Windows 10 Home

wp

  • Hero Member
  • *****
  • Posts: 11853
Re: Correct display of values in logarithmic scales in TAChart
« Reply #7 on: July 03, 2017, 05:40:32 pm »
In the meantime I uploaded a preliminary version of support for html tags embedded within TAChart labels and titles. These tags are supported:
  • <sub> ... </sub>  ---> subscript
  • <sup> ... </sup>  ---> superscript
  • <b> ... </b> ---> bold
  • <i> ... </i> ---> italic
  • <u> ... </u> ---> underline
  • <s> ... </s> ---> strikeout
  • <font color="red"> ... </font>  --> red (or any other valid html color code)
  • <font name="Courier"> ... </font> --> Switch font to "Courier" (or any other font known in the system) (BUT: not recommended because different fonts are not correctly aligned vertically)
  • HTML entities are converted to UTF8 codepoints. The title of the x axis, for example could contain the text "sin &beta;" to show "sin β" with perfect Greek characters.
This feature is activated by switching the new property TextFormat of the label or title to tfHTML.

Still some bugs here and there, but good enough for testing...

Note: This version is available only in Lazarus trunk, it will not be backported to the upcoming version 1.8 because it is a new feature.

In the demo program above you must change these lines in CreateAxislabels:
Code: Pascal  [Select][+][-]
  1. //    ASource.Add(x, x, Format('10^%.0f', [Log10(x)]));   // <--- remove this
  2.     ASource.Add(x, x, Format('10<sup>%.0f</sup>', [Log10(x)]));     // <--- add this
And set TextFormat of BottomAxis.Marks and LeftAxis.Marks to tfHTML.
« Last Edit: July 03, 2017, 06:34:12 pm by wp »

maurobio

  • Hero Member
  • *****
  • Posts: 623
  • Ecology is everything.
    • GitHub
Re: Correct display of values in logarithmic scales in TAChart
« Reply #8 on: July 03, 2017, 10:22:19 pm »
Dear wp,

A really great improvement to TAChart, which is fast on the way to become one of the main plotting packages for the development of scientific and financial applications in the open source world.

I will try and figure out how to install from the Lazarus trunk, but this will have to wait a few more days until I finish the implementation of my text analysis applications (which has TAChart as one of its core components). Anyway, it is nice to know that this new funcionality will be available in future releases of Lazarus.

With warmest regards,
UCSD Pascal / Burroughs 6700 / Master Control Program
Delphi 7.0 Personal Edition
Lazarus 2.0.12 - FPC 3.2.0 on GNU/Linux Mint 19.1, Lubuntu 18.04, Windows XP SP3, Windows 7 Professional, Windows 10 Home

 

TinyPortal © 2005-2018