Labels not always showing lazarus / 55-TAChart ---------------------------------------------------------------------- fpcoder · 2017-02-07 20:27 The X-axis values don't always show for some reason. Plus it shows only the year, not the month although 'mmm yyyy' is specified. What am I missing? Here's how records are added: (Sample attached. It plots data from an included csv file) 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     //Always give the first point a year and month    if aRow = 0 then    //If current year larger than old year, set label    else if YearOf(dt) > OldYear then      lcsSeries.AddXYList(aRow, ylist, FormatDateTime('mmm yyyy', dt, aFormatSettings))    //All other should have no labels    else      lcsSeries.AddXYList(aRow, ylist, ''); ---------------------------------------------------------------------- wp · 2017-02-07 22:19 I see several issues: You want special labels, and you add them to the data points skipping those which should remain unlabeled. This is not a good strategy for two reasons: (1) You must be sure that data points sit exactly at the x values which you want to label (suppose you want a label at "0", but none of your data points is there?) (2) TAChart follows its own strategy for selecting labels, it is very difficult to control this. In your case it always picks the labels which are empty. Therefore, you only see the first label. How to avoid this? Use a separate chartsource which just contains x values and the mark texts for the positions to be labeled.After these changes I still did not see the intended labels. This is because you did not initialize the OldYear variable outside the loop. It must have had a very large random value because the condition "YearOf(dt) > OldYear" never came true. Instead of outside the loop I put initialization of OldYear into the "if row = 0" condition which makes sure that the very first label is shown but no other one of the same year.Not a bug at the moment, but it will be one if you call PopulateSeries several times: You must clear the chartsources before adding new data, otherwise data will be added to the ones previously loaded.My country settings define the comma as decimal separator. You do prepare special FormatSettings to take care of this (great!), but you must add these FormatSettings to StrToFloat as well to make sure that the decimal point in the csv strings is detected correctlyFinally I wondered why I never saw the month in your labels in a WriteLn of the labels although you had specified the format string to include month. This is because you initialized only a few fields of the special FormatSettings, the other fields, i.e. the month names, are undefined. Assign the DefaultFormatSettings to your FormatSettings before applying your own modifications.Here is the code which works correctly for me. As I said, there's an additional ListChartSource (called YearLabels) on the form. 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 { TfrmMain } procedure TfrmMain.FormCreate(Sender: TObject);begin  Chart.BottomAxis.Marks.Source:= YearLabels;  Chart.LeftAxis.Alignment:=calRight;  CSV:= TCSVDocument.Create;  if FileExists('msft.csv') then    CSV.LoadFromFile('msft.csv');   PopulateSeries;end; procedure TfrmMain.PopulateSeries;var  aRow: integer;  dt: TDateTime;  ylist: array [0..3] of double;  OldYear: Word;begin  YearLabels.Clear;  lcsSeries.Clear;   for aRow:= 0 to CSV.RowCount -1 do  begin    dt:= StrToDateTime(CSV.Cells[csvDATE,aRow], aFormatSettings);    ylist[yOPEN]:= StrToFloat(CSV.Cells[csvOPEN,aRow], aFormatSettings);  ylist[yHIGH]:= StrToFloat(CSV.Cells[csvHIGH, aRow], aFormatSettings);    ylist[yLOW]:= StrToFloat(CSV.Cells[csvLOW, aRow], aFormatSettings);    ylist[yCLOSE]:= StrToFloat(CSV.Cells[csvCLOSE, aRow], aFormatSettings);     lcsSeries.AddXYList(aRow, ylist);     //Always give the first point a year and month    if aRow = 0 then begin      YearLabels.Add(aRow, aRow, FormatDateTime('mm/yyyy', dt, aFormatSettings));      OldYear := YearOf(dt);    end    //If current year larger than old year, set label    else if YearOf(dt) > OldYear then begin      YearLabels.Add(aRow, aRow, FormatDateTime('yyyy', dt, aFormatSettings));      OldYear := YearOf(dt);    end;    //All others should have no labels  end;end; initialization  aFormatSettings := DefaultFormatSettings;  aFormatSettings.DecimalSeparator:='.';  aFormatSettings.DateSeparator:= '-';  aFormatSettings.TimeSeparator:= ':';  aFormatSettings.LongDateFormat:= 'yyyy-MMM-dd';  aFormatSettings.ShortDateFormat:= 'yyyy-MM-dd';  aFormatSettings.ShortTimeFormat:= 'hh:nn';  aFormatSettings.LongTimeFormat:= 'hh:nn:ss'; Maybe you are interested in a similar program that I once wrote for displaying historic financial share values (https://sourceforge.net/p/wp- laz/code/HEAD/tree/FinancialChart/trunk/). It downloads the share prices from free internet servers. ---------------------------------------------------------------------- fpcoder · 2017-02-08 10:36 A separate chartsource for BottomAxis did the trick. I went ahead and added one more chartsource called DayLabels. It is switched to by code in the OnExtentChanged event if PointsInRange are less than 100. Zoom out and it switches back to using the YearLabels chartsource. (Ctrl + Mousewheel) At some zoomlevels, the labels get crowded. I would like them to never be closer to eachother than 5 millimeter or so, but didn't manage yet. Also the Y scale starts at zero but there is no data until 15 so some of  the chart area is wasted. How to change that? (Forgot to clear the DayLabels before uploading the sample  ) ---------------------------------------------------------------------- wp · 2017-02-08 11:53 The decision to use an external Chartsource for the axis labels means that you have full control over label positioning but it means also that you must decide on every details, there's no more automatism (except for Marks.OverlapPolicy = opNeighbar - but I don't like it because it results in irregular intervals). To avoid overlapping to the degree of several millimeters you must calculate the length of the labels and consider this when positioning labels. There were some discussions here with examples, please use the forum search, maybe seek for "DateTimeInterval" and my alias. Alternatively you could make a rough classification depending on the zoomed extent: - If the extent is shorter than 10 days put labels at every day - shorter than 1 month: --> every week start day (Sunday or Monday, depending on country) - shorter than 1 year: --> every 1st of a month etc. Or: Why don't you use a DateTimeIntervalChartSource for the zoomed case? In my eyes it works nicely for this purpose. Using its Params.MinLength/MaxLength you can control overlapping very efficiently without turning OverlapPolicy on. Its only disadvantage is that it does not necessarily put labels at the start of a date/time entity, i.e. it may decide to label the 2nd of a month while it could label the 1st as well. Your DayLabels are very long (format 'dd/mm yyyy'). How about adding a linebreak? 'dd/mm' + LineEnding +'yyyy'. The y axis normally starts automatically at the data minimum. Since it does not and since you don't override any of the related settings I had a look at the data, and in fact there are a few rows for which the open, high and low values are missing and have been replaced by a zero value (rows 230, 250, 255 and some more). For these days only the close tick is painted (zoom around 25-12 2008). You may want to set the open, high, low values equal to the close value in these cases instead. This should avoid the y axis to start at zero.