Correct display of values in logarithmic scales in TAChart lazarus / 55-TAChart ---------------------------------------------------------------------- maurobio · 2017-06-30 13:25 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program project1; {$mode objfpc}{$H+} uses  {$IFDEF UNIX}{$IFDEF UseCThreads}  cthreads,  {$ENDIF}{$ENDIF}  Interfaces, // this includes the LCL widgetset  Forms, Unit1, tachartlazaruspkg  { you can add units after this }; {$R *.res} begin  RequireDerivedFormResource:=True;  Application.Initialize;  Application.CreateForm(TForm1, Form1);  Application.Run;end. unit Unit1; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, FileUtil, TAGraph, TASeries, TATransformations, Forms,  Controls, Graphics, Dialogs, Math; type   { TForm1 }   TForm1 = class(TForm)    Chart1: TChart;    ChartAxisTransformations1: TChartAxisTransformations;    ChartAxisTransformations1LogarithmAxisTransform1: TLogarithmAxisTransform;    Series1: TLineSeries;    procedure FormCreate(Sender: TObject);    procedure FormDestroy(Sender: TObject);  private    { private declarations }  public    { public declarations }  end; var  Form1: TForm1; implementation {$R *.lfm} { TForm1 } procedure TForm1.FormCreate(Sender: TObject);var   I: Integer;   Frequency: array[1..12] of Integer;begin  for I := 1 to 12 do      Frequency[I] := 1;  Frequency[1] := 2;  for I := 1 to 12 do begin      //Series1.AddXY(Log2(I), Log2(Frequency[I]));      Series1.AddXY(I, Frequency[I]);  end;end; procedure TForm1.FormDestroy(Sender: TObject);begin  Chart1.SaveToFile(TPortableNetworkGraphic, 'project1.png');end; end. object Form1: TForm1  Left = 237  Height = 398  Top = 120  Width = 775  Caption = 'Form1'  ClientHeight = 398  ClientWidth = 775  OnCreate = FormCreate  OnDestroy = FormDestroy  LCLVersion = '1.6.0.4'  object Chart1: TChart    Left = 0    Height = 398    Top = 0    Width = 775    AxisList = <          item        Grid.Visible = False        Intervals.Count = 2        Intervals.Tolerance = 100        Marks.Format = '%0.0e'        Marks.Style = smsCustom        Minors = <>        Title.LabelFont.Height = -13        Title.LabelFont.Orientation = 900        Title.Visible = True        Title.Caption = 'frequency (log)'      Transformations = ChartAxisTransformations1      end          item        Grid.Visible = False        Alignment = calBottom        Marks.Format = '%0.0e'        Marks.Style = smsCustom        Minors = <>        Title.LabelFont.Height = -13        Title.Visible = True      Title.Caption = 'rank (log)'        Transformations = ChartAxisTransformations1      end>    BackColor = clWhite    Foot.Brush.Color = clBtnFace    Foot.Font.Color = clBlue    Title.Brush.Color = clBtnFace    Title.Font.Color = clBlack    Title.Font.Height = -16    Title.Font.Style = [fsBold]    Title.Text.Strings = (      'Plot of word frequency'    )    Title.Visible = True    Align = alClient    Color = clWhite    object Series1: TLineSeries      LinePen.Color = clTeal      LinePen.Width = 2      Pointer.Brush.Color = clTeal      Pointer.Pen.Color = clTeal    Pointer.Style = psCircle      ShowPoints = True    end  end  object ChartAxisTransformations1: TChartAxisTransformations    left = 200    top = 8    object ChartAxisTransformations1LogarithmAxisTransform1: TLogarithmAxisTransform      Base = 10    end  endend Thanks in advance for any assistance you can provide! With warmest regards, ---------------------------------------------------------------------- wp · 2017-06-30 15:23 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.Chart1AxisList1MarkToText(var AText: String; AMark: Double); var  s: String;  ex: Integer;begin  s := Format(Chart1.LeftAxis.Format, [AMark]);  ex := StrToInt(Copy(AText, pos('E', AText) + 1));  AText := Copy(AText, 1, pos('E', AText)-1) + ' × 10' + IntToStr(ex) + '';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 labelsStill - 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 · 2017-06-30 15:54 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, ---------------------------------------------------------------------- wp · 2017-06-30 16:51 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 · 2017-06-30 19:19 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! Warmest regards, ---------------------------------------------------------------------- wp · 2017-06-30 21:44 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 h ttp://wiki.lazarus.freepascal.org/TAChart_Tutorial:_ListChartSource,_L ogarithmic_Axis,_Fitting how to get this done. Also, look at the source code of the demo, it contains more comments explaining some details. ---------------------------------------------------------------------- maurobio · 2017-06-30 22:12 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!  With warmest regards, ---------------------------------------------------------------------- wp · 2017-07-03 15:40 In the meantime I uploaded a preliminary version of support for html tags embedded within TAChart labels and titles. These tags are supported: ...   ---> subscript ...   ---> superscript ... ---> bold ... ---> italic ... ---> underline ... ---> strikeout ...   --> red (or any other valid html color code) ... --> 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 β" 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i //    ASource.Add(x, x, Format('10^%.0f', [Log10(x)]));   // <--- remove this    ASource.Add(x, x, Format('10%.0f', [Log10(x)]));   // <--- add thisAnd set TextFormat of BottomAxis.Marks and LeftAxis.Marks to tfHTML. ---------------------------------------------------------------------- maurobio · 2017-07-03 20:22 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,