Page 1 of 2

Howto make automatic labels of the left axis be a multiple of some value

Posted: Tue Aug 01, 2023 10:07 am
by 15685014
Hello.
I need to make automatic labels of the left axis be a multiple of 125. And ensure horizontal gridlines to be drawn for every label.
So that my chart would look something like this (depending on the actual Y values):
1.png
1.png (48.39 KiB) Viewed 77087 times
2.png
2.png (51.56 KiB) Viewed 77087 times

Re: Howto make automatic labels of the left axis be a multiple of some value

Posted: Tue Aug 01, 2023 11:06 am
by Christopher
Hello,

I think this does it for you:

Code: Select all

        public Form1()
        {
            InitializeComponent();

            var line1 = new Line(tChart1.Chart);
            var line2 = new Line(tChart1.Chart);

            var rnd = new Random();
            var max = 900;

            for (int i = 0; i < 50; i++)
            {
                line1.Add(rnd.Next(max));
                line2.Add(rnd.Next(max));
            }

            tChart1.Axes.Left.Increment = 125;
            tChart1.Axes.Left.Labels.Separation = 1;
            tChart1.Axes.Left.Grid.DrawEvery = 1;
            tChart1.Axes.Left.AutomaticMinimum = false;
            tChart1.Axes.Left.Minimum = 0;
            tChart1.Axes.Left.GetAxisDrawLabel += Left_GetAxisDrawLabel;
        }

        private void Left_GetAxisDrawLabel(object sender, GetAxisDrawLabelEventArgs e)
        {
            e.DrawLabel = e.LabelValue % 125 == 0;
        }
Try changing the value of 'max'.

Re: Howto make automatic labels of the left axis be a multiple of some value

Posted: Tue Aug 01, 2023 11:38 am
by 15685014
Thank you. That is exactly what I need. Only one question left: what does tChart1.Axes.Left.Labels.Separation = 1; stand for? I see no changes on a chart when adjusting that value (I've tried 2, 3, 5 and 10).

Re: Howto make automatic labels of the left axis be a multiple of some value

Posted: Tue Aug 01, 2023 2:07 pm
by Christopher
Hello,

in theory it:
Screenshot from 2023-08-01 15-45-53.png
Screenshot from 2023-08-01 15-45-53.png (17.83 KiB) Viewed 77077 times
but it doesn't seem to work very well. What does work is setting max to a high value (e.g. 9000) and setting Separation to 0—here we can see that it leaves no minimum distance, as it should.

Re: Howto make automatic labels of the left axis be a multiple of some value

Posted: Wed Aug 02, 2023 5:23 am
by 15685014
I guess you have a TeeChart.xml file. Could you share it so I don't have to go online every time I need a property description. Thank you.

Re: Howto make automatic labels of the left axis be a multiple of some value

Posted: Wed Aug 02, 2023 7:48 am
by Christopher
There's a Steema.TeeChart.chm file shipped in the TeeChart NuGet packages which has the xml documentation compiled into it. This is what we would suggest you use for 'offline' API documentation.
Screenshot from 2023-08-02 09-46-43.png
Screenshot from 2023-08-02 09-46-43.png (102.4 KiB) Viewed 77040 times

Re: Howto make automatic labels of the left axis be a multiple of some value

Posted: Wed Aug 02, 2023 8:05 am
by 15685014
But I would like to see function/property description right into IntelliSense. Could you share TeeChart.xml please.

Re: Howto make automatic labels of the left axis be a multiple of some value

Posted: Wed Aug 02, 2023 8:10 am
by 15685014
I have done further testing and found that your code does not always work correctly. I you change 125 to 350 and set max = 8000 - it is ok:
Безымянный.png
Безымянный.png (74.46 KiB) Viewed 77038 times
But you set max = 9000 (and more) - most labels are not multiples of 350:
Безымянный1.png
Безымянный1.png (64.71 KiB) Viewed 77038 times
I've expected auto labels to be set to a multiple of 350 (for example 0, 1750, 3500, 5250, 7000 and 8750). Are there any workarounds?

Re: Howto make automatic labels of the left axis be a multiple of some value

Posted: Thu Aug 03, 2023 7:52 am
by Christopher
Hello,

for finer control, you can use the GetNextAxisLabel event, e.g.

Code: Select all

        const int _increment = 350;
        const int _max = 20000;

        public Form1()
        {
            InitializeComponent();

            var line1 = new Line(tChart1.Chart);
            var line2 = new Line(tChart1.Chart);

            var rnd = new Random();

            for (int i = 0; i < 50; i++)
            {
                line1.Add(rnd.Next(_max));
                line2.Add(rnd.Next(_max));
            }

            tChart1.Axes.Left.Increment = _increment;
            tChart1.Axes.Left.Labels.Separation = 1;
            tChart1.Axes.Left.Grid.DrawEvery = 1;
            tChart1.Axes.Left.AutomaticMinimum = false;
            tChart1.Axes.Left.Minimum = 0;
            tChart1.GetNextAxisLabel += TChart1_GetNextAxisLabel;
        }

        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
            tChart1.Header.Text = $"v.{Utils.Version}, size: {tChart1.Height}x{tChart1.Width}, increment: {_increment}, max: {_max}";
        }

        private void TChart1_GetNextAxisLabel(object sender, GetNextAxisLabelEventArgs e)
        {
            var multiplier = Utils.Round(tChart1.Axes.Left.Maximum / _increment / 10);

            int GetValue(int index)
            {
                return _increment * multiplier * index;
            }
            if (sender == tChart1.Axes.Left)
            {
                e.Stop = false;
                switch (e.LabelIndex)
                {
                    case 0: e.LabelValue = 0; break;
                    case 1: e.LabelValue = GetValue(1); break;
                    case 2: e.LabelValue = GetValue(2); break;
                    case 3: e.LabelValue = GetValue(3); break;
                    case 4: e.LabelValue = GetValue(4); break;
                    case 5: e.LabelValue = GetValue(5); break;
                    case 6: e.LabelValue = GetValue(6); break;
                    case 7: e.LabelValue = GetValue(7); break;
                    case 8: e.LabelValue = GetValue(8); break;
                    case 9: e.LabelValue = GetValue(9); break;
                    default: e.Stop = true; break;
                }
            }
        }
Screenshot from 2023-08-03 09-50-40.png
Screenshot from 2023-08-03 09-50-40.png (261.52 KiB) Viewed 77012 times
I'm working on getting the xml file to you and will do so when I can.

Re: Howto make automatic labels of the left axis be a multiple of some value

Posted: Thu Aug 03, 2023 8:34 am
by Christopher
A more generic solution would be:

Code: Select all

        private void TChart1_GetNextAxisLabel(object sender, GetNextAxisLabelEventArgs e)
        {
            var max_labels = 20;
            var num = Utils.Round(_max / _increment);
            num = num >= max_labels ? max_labels : num;
            var multiplier = Utils.Round(_max / _increment / num);

            int GetValue(int index)
            {
                return _increment * multiplier * index;
            }

            if (sender == tChart1.Axes.Left)
            {
                e.Stop = false;

                if(e.LabelIndex <= num)
                {
                    e.LabelValue = GetValue(e.LabelIndex);
                }
                else 
                {
                    e.Stop = true;
                }
            }
        }
Screenshot from 2023-08-03 10-34-03.png
Screenshot from 2023-08-03 10-34-03.png (265.58 KiB) Viewed 77007 times

Re: Howto make automatic labels of the left axis be a multiple of some value

Posted: Thu Aug 03, 2023 3:11 pm
by Christopher
bairog wrote:
Wed Aug 02, 2023 8:05 am
But I would like to see function/property description right into IntelliSense. Could you share TeeChart.xml please.
I've uploaded new NuGet packages containing the necessary xml documentation comments—they are only needed in .NET Framework, according to my tests, as Visual Studio is somehow able to read these comments directly from .NET Core assemblies without the need for the xml file.

Re: Howto make automatic labels of the left axis be a multiple of some value

Posted: Fri Aug 04, 2023 7:00 am
by 15685014
Christopher wrote:
Thu Aug 03, 2023 8:34 am
A more generic solution would be:
Your code is not working very well when _max / _increment is close to a multiple of max_labels but is slightly less.
In your specific example (max_labels = 20 and _increment = 175) you can just set _max = 13900 (13900 / 175 = 79.428) and get the following picture (there is a big gap between the last label and left axis actual maximum):
Безымянный.png
Безымянный.png (74.38 KiB) Viewed 76978 times
I have tested some workarounds and the best I have come up with is changing _multiplier formula from Utils.Round(_max / _increment / _num) to (Int32)Math.Round((Double)_max / _increment / _num). With this approach, a greater multiplier is chosen in 50% cases.
So the situation I've decribed (max_labels = 20, _increment = 175 and _max = 13900) becomes:
Безымянный1.png
Безымянный1.png (72.19 KiB) Viewed 76978 times
My approach is not always perfect: when (Double)_max / _increment / _num is close to n.5 but slightly less there is same gap (but it is 2 times smaller). For example for _max = 12200 (12200/175/20 = 3.485, so _multiplier is still 3) I get the following picture:
Безымянный2.png
Безымянный2.png (72.11 KiB) Viewed 76978 times
If you have any ideas how to further improve my adjusted algorithm - please share it. Thank you.

Re: Howto make automatic labels of the left axis be a multiple of some value

Posted: Fri Aug 04, 2023 8:03 am
by Christopher
bairog wrote:
Fri Aug 04, 2023 7:00 am
If you have any ideas how to further improve my adjusted algorithm - please share it. Thank you.
How about:

Code: Select all

         private void TChart1_GetNextAxisLabel(object sender, GetNextAxisLabelEventArgs e)
        {
            var mod = _max % _increment;
            var local_max = _max;

            if(mod != 0) 
            {
                local_max = _max + (_increment - mod);
            }

            var max_labels = 20;
            var num = Utils.Round(local_max / _increment);
            var multiplier = Utils.Round(num / max_labels);

            int GetValue(int index)
            {
                return _increment * multiplier * index;
            }

            if (sender == tChart1.Axes.Left)
            {
                e.Stop = false;

                if(e.LabelIndex <= num)
                {
                    e.LabelValue = GetValue(e.LabelIndex);
                }
                else 
                {
                    e.Stop = true;
                }
            }
        }

Re: Howto make automatic labels of the left axis be a multiple of some value

Posted: Fri Aug 04, 2023 8:40 am
by 15685014
Unfortunately with this code labels count can greatly exceed max_labels value. For example for _max = 5300 the are 30 labels:
Безымянный.png
Безымянный.png (69.46 KiB) Viewed 76969 times

Re: Howto make automatic labels of the left axis be a multiple of some value

Posted: Fri Aug 04, 2023 8:49 am
by Christopher
bairog wrote:
Fri Aug 04, 2023 8:40 am
Unfortunately with this code labels count can greatly exceed max_labels value. For example for _max = 5300 the are 30 labels:
Yes, that's true. But I'm sure you get the idea now of what the TeeChart possibilities are, and so can adapt your code to them.