I agree that axis labeling of TAChart may be difficult to understand.
The problem is that there are several conflicting requirements: nice intervals and density of labels. "Nice" intervals, or "nice steps", means: I want labels 0, 2, 4, 6, 8 10, but not 0, 1.232, 2.464, 5.918 etc. "Densitiy of labels" means:the labels should not be too close (and overlap), but also there should be "enough" labels, not only - say - two.
Let me give you an example (I don't know if I can describe the algorithm exactly, but you should catch its principle).
Suppose the axis ranges between -1 and 11. Suppose at first that
aipUseCount is the only Option checked. Then all other parameters of the Intervals are ignored except for the
Count which is 5 by default. This means that there will be 5 intervals (i.e. 6 labels) between -1 and 11: the first label is -1, the last label is at 11, and the others will be at equally-spaced increments of (11-(-1) / 5 = 2.4 --> there will be labels at -1, 1.4, 3.8, 6.2, 8.6 and 11.
Well - these are not "nice" numbers (although they could still be much worse!)
Therefore, the aipUseCount is normally not very useful (although there can be opposite cases). Normally you should stick to the default Options:
aipUseNiceSteps, aipUseMinLength, aipUseMaxLength. This operation conditions are primarily determined by the values specified in the "
NiceSteps" property: "0.2|0.5|1.0" by default. Let me modify it to "2|5|10" - it has the same effect, but is easier to explain:
The algorithm begins with the first number, 2, and checks which multiples of 2 would fit into the data range: 0, 2, 4, 6, 8, 10 - Very nice numbers. The algorithm could stop here, but this is just due to the selection of the numbers we started with.
The next step is to calculate the distance, in pixels, between adjacent label centers, in other words, between the grid lines belonging to these labels. This distance is compared with the values entered for
MinLength and
MaxLength.
There are three cases
(1) The
distance is between MinLength and MaxLength --> the current label interval (2) is fine, and labels will be selected to be at 0, 2, 4, 6, 8, 10
(2) If the
distance is larger than MaxLength (i.e. the labels are too much apart) then the algorithm picks the next value in the NiceSteps, 5. The labels now would be drawn at 0, 5, 10. If the distance between these labels is too large again, the next number would be picked once more: 10. And we would be left with labels at 0 and 10 only. etc. And in case of very small charts and / or unfavorable MaxLength, the algorithm could even go one step further and end up with one label left at 0.
(3) The
distance is smaller than MinLength (i.e. the labels are too close). Then the algorithm picks the next smaller number from the NiceSteps list. Well, in this case, the 2 was the first number in the list, therefore, the program picks now the last number and divides it by 10, i.e. we select an interval length of 10/10 = 1. Now our labels would be at -1, 0, 1, 2, 3, 4, 5, 6 7, 8, 9, 10, 11. If the distance of these labels still would be smaller than MinLength the next test interval would be 5/10 = 0.5 --> -1, -0.5, 0, 0.5, 1, 1.5, ... etc.
I hope you understand now that the values specified between the bar characters in the NiceSteps define the basic steps used for label increments. These steps are multipied by 10, 100, or 0.1, 0.01 etc as needed for the data range. It is not important wether NiceSteps is specified as "0.2|0.5|1.0" or "2|5|10" or "20|50|100" etc. You may even change the order (i.e. use "1|2|5").
Why use 1, 2 and 5? Because these are the only integer numbers with which you can span a full decade (e.g., 0, 2, 4, 6, 8, 10). If you would add a "3" to the NiceSteps ("1|2|3|5") then our example might lead to labels like 0, 3, 6, 9, which may look ok here but could get very terrible in more general cases.
The NiceSteps of the first post above, '0.1|0.5|1.0', contains a redundant 1, you can skip either the 0.1 or the 1.0 because it will be tested anyway, depending on the MinLength/MaxLength values. But having the redundant value in the NiceSteps does not affect the label selection process.
Using the
DateTimeChartSource it may be a good idea to modify the NiceSteps because the base order of magnitude on time scales is not a factor 10 but the factor 60 (1 hour = 60 min, 1 min = 60 sec), or 24 (1 day = 24 hours). Therefore, I recommended in the other thread to replace the NiceSteps by "1|2|3", i.e labels at 0, 10, 20, 30, 40, 50 seconds, or at 0, 20, 40 sec, or at 0, 30 sec. This is for minute and second units (Steps). For hours, I'd use NiceSteps = '1|2|4|6|12', similarly for months. Years should use the normal settings. With days there's the problem that the natural period length varies: a month may be 28, 29, 30, or 31 days long, and whatever parameters you select, the 1st label of a month will always drift. This is still an issue.
Or if you plot an
angle the basic period is - maybe - 90 degrees. Here you may also want increments of 15 (0, 15, 30, 45, 60,...) or 30 (0, 30, 60, 90), or 45 (45, 90), i.e. NiceSteps = '10|15|30|45|90', or similar. Here it is very important that MinLength and MaxLength are selected correctly because if the algorithm picks the 90 and divides it by 10 you will see labels at 0, 9, 18, 27, etc.
A difficult case is given by
logarithmic charts. Here the logarithms of values are plotted on an invisible linear plot, like on old-fashioned graph paper. The units on the graph paper are called "graph units" by TAChart, those of the original numbers are "axis units". The labelling algorithm normally uses the axis units to calculate the intervals. But on a log axis the intervals are not constant, and an interval found at one end of the axis is too close (or too wide) on the other end. Therefore, there's the option aipGraphCoords which switches the labeling algorithm to use the graph units, i.e. the log values. Suppose that data extends from 1 to 1000, the decadic logarithms are 0 and 3. The labeller finds the intervals 0, 1, 2, 3 and after inverting the log operation we end up with labels at 10^0 = 1, 10^1 = 10, 10^2 = 100 and 10^3 = 1000.
Unfortunately, it is very difficult to find the correct parameter settings for "nice" log axes. It is advisable to enter a small number (like 3 or 5) to the Tolerance property in order to the reduce the effect of round-off errors. And the NiceSteps should be set at runtime to "Format('%f|%f|%f', [log10(1), log10(2), log10(5)])" - this puts more emphasis on selecting "nice" decadic intermediate values.
I hope this lengthy description explains some of the mystery behind the TAChart axis labels. Maybe I'll add it to the TAChart tutorial series (
http://wiki.lazarus.freepascal.org/TAChart#Documentation).