LinearAxis3D does not always honor the Maximum value property

9 posts, 1 answers
  1. Joe
    Joe avatar
    65 posts
    Member since:
    Nov 2017

    Posted 19 Jun Link to this post

    I'm using RadCartesianChart3d to show a surface.  I've written some background code to intelligently choose the Maximum and Minimum values for my Z axis to be on nice even numbers which exceed the boundaries of the data.  I then bind the LinearAxis3D for Z to these values.

    The chart honors my Minimum value.  Unfortunately, it sometimes ignores my Maximum value and chooses its own.  

    To be sure I wasn't wasting your time, before I posted this report, I tried to reproduce the problem using the sample application that Martin Ivanov attached in a reply in this other forum thread from just 2 weeks ago.  It's the attachment "WpfApp17"

    https://www.telerik.com/forums/dynamic-colorizer-for-surfaceseries3d

    What I did was change the Z axis  in the sample to use some arbitrary Minimum and Maximum values:

    <telerik:RadCartesianChart3D.ZAxis>
        <telerik:LinearAxis3D Minimum="-800"  Maximum="900"/>
    </telerik:RadCartesianChart3D.ZAxis>

    At first, I could not reproduce the problem.  But then I tried updating the sample to use the very latest version of UI for WPF that I have on my machine.  It is R2 2019 SP1 which was literally released today, June 19, 2019.   

    Once I changed the assembly references to use the this new version of UI for WPF, the problem did occur.  When I run the sample app with the changes above, my maximum axis value only shows 700, not 900.  

    (I realize the data does not go that high but I still want the chart to show the maximum I give to it.)

    That's not all.  It gets even stranger.  If you then change the Maximum value from 900 to 1200, suddenly, it *is* honored.


    The forum software does not seem to want to let me attach my modified version of the sample to this thread, even though it's a ZIP file and it's only 350k so you'll need to make the changes on your own version to reproduce this.




  2. Martin Ivanov
    Admin
    Martin Ivanov avatar
    2240 posts

    Posted 24 Jun Link to this post

    Hello Joe,

    This is quite curious. I am not aware of the reported behavior. Would it be possible for you to send some runnable code snippets which I can test on my side.

    As for the forum attachments, indeed, it allows only pictures. If you want to share a project, you can do it via the support ticketing system.

    Regards,
    Martin Ivanov
    Progress Telerik
    Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
  3. Joe
    Joe avatar
    65 posts
    Member since:
    Nov 2017

    Posted 26 Jun in reply to Martin Ivanov Link to this post

    Hi Martin,

    (I must have missed the notification that you replied or I would have replied back sooner myself)

    As for some usable code snippets, well all you need to do is make a minor modification to that very same sample from the other forum thread that I linked to.  However if you would like to see the modified version I am using I have pasted the XAML and code-behind of the MainWindow from that project as I modified it.

    First, here is the MainWindow.Xaml  (remember this is your sample, just slightly modified by me)

     

    <Window x:Class="WpfApp17.MainWindow"
            xmlns:local="clr-namespace:WpfApp17"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800">
        <Grid>
            <telerik:RadCartesianChart3D>
                <telerik:RadCartesianChart3D.XAxis>
                    <telerik:LinearAxis3D/>
                </telerik:RadCartesianChart3D.XAxis>
                <telerik:RadCartesianChart3D.YAxis>
                    <telerik:LinearAxis3D />
                </telerik:RadCartesianChart3D.YAxis>
                <telerik:RadCartesianChart3D.ZAxis>
     
                    <!-- In my testing, the maximum value of 900 is NOT honored but a max of 1200 IS honored -->
     
                    <telerik:LinearAxis3D Minimum="-800"  Maximum="1200"/>
     
                </telerik:RadCartesianChart3D.ZAxis>
     
                <telerik:RadCartesianChart3D.Series>
                    <telerik:SurfaceSeries3D ItemsSource="{Binding Points}"
                                             XValueBinding="X"
                                             YValueBinding="Y"
                                             ZValueBinding="Z"
                                             x:Name="Series">
                        <telerik:SurfaceSeries3D.Colorizer>
                            <telerik:SurfaceSeries3DValueGradientColorizer x:Name="Colorizer" IsAbsolute="False" />
                        </telerik:SurfaceSeries3D.Colorizer>
                    </telerik:SurfaceSeries3D>
                </telerik:RadCartesianChart3D.Series>
                <telerik:RadCartesianChart3D.Grid>
                    <telerik:CartesianChart3DGrid />
                </telerik:RadCartesianChart3D.Grid>
                <telerik:RadCartesianChart3D.Behaviors>
                    <telerik:Chart3DCameraBehavior />
                </telerik:RadCartesianChart3D.Behaviors>
            </telerik:RadCartesianChart3D>
     
            <telerik:RadSlider Minimum="0" Maximum="63" SmallChange="1" LargeChange="1" VerticalAlignment="Bottom" Margin="10" x:Name="border" IsSelectionRangeEnabled="True" SelectionChanged="Border_SelectionChanged"/>       
        </Grid>
    </Window>

     

    Here is the code-behind MainWindow.xaml.cs

     

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows;
    using System.Windows.Media;
     
    namespace WpfApp17
    {
        public partial class MainWindow : Window
        {
            private static Random r = new Random();
            private List<Color> ColorsCollection = new List<Color>();
     
            public MainWindow()
            {
                InitializeComponent();
     
                int rMax = Colors.Red.R;
                int rMin = Colors.Blue.R;
                int bMax = Colors.Red.B;
                int bMin = Colors.Blue.B;
                int gMax = Colors.Red.G;
                int gMin = Colors.Blue.G;
                     
                int size = 64;
     
                for (int i = 0; i < size; i++)
                {
                    var rAverage = rMin + (int)((rMax - rMin) * i / size);
                    var gAverage = gMin + (int)((gMax - gMin) * i / size);
                    var bAverage = bMin + (int)((bMax - bMin) * i / size);
                    ColorsCollection.Add(Color.FromRgb((byte)rAverage, (byte)gAverage, (byte)bAverage));
                }
     
                this.Colorizer.GradientStops = GetGradientStops(0, ColorsCollection.Count - 1);
                this.border.Background = new LinearGradientBrush(this.Colorizer.GradientStops);
     
                List<PlotInfo> data = new List<PlotInfo>();
                double maxX = 100;
                double maxY = 80;
     
                for (int x = 0; x < maxX; x++)
                {
                    for (int y = 0; y < maxY; y++)
                    {
                        double xValue = Math.Sin(x * Math.PI / (0.25 * maxX));
                        double yValue = Math.Cos(y * Math.PI / (0.50 * maxY));
                        double z = 200 * xValue * yValue;
                        PlotInfo pi = new PlotInfo { X = x, Y = y, Z = z, };
                        data.Add(pi);
                    }
                }
     
                this.Series.ItemsSource = data;
            }
     
            private GradientStopCollection GetGradientStops(int startIndex, int endIndex)
            {
                var colors = ColorsCollection.Skip(startIndex).Take(endIndex - startIndex);
                var step   = 1.0 / colors.Count();
                var stops  = colors.Select((color, index) => new GradientStop(color, index * step));
                return new GradientStopCollection(stops);
            }
     
            private void Border_SelectionChanged(object sender, Telerik.Windows.RadRoutedEventArgs e)
            {
                this.Colorizer.GradientStops = GetGradientStops((int)this.border.SelectionStart, (int)this.border.SelectionEnd);
            }
        }
     
        public class PlotInfo
        {
            public double X { get; set; }
            public double Y { get; set; }
            public double Z { get; set; }
        }
    }

     

     

     

     

    This is causing me  problems in my production application.  The Surface I draw renders well and the chart shows the X and Y axes fully.  But in my case,  I cannot make it show any label on the Z axis besides the minimum label

    I've attached an image showing what I see.

    Below is the xaml I'm using in my production app for the chart you see in the attached image.  Note that I've stripped the Z axis down to its minimum settings (just SmartLabelsMode) in the hopes to make it show *something* more than just the one label.  But believe me, I have tried every combination of LinearAxis3D properties I can find for the labels, including  "SmartLabelsMode", TickOrigin, MajorStep, Minimum and Maximum properties.  I've tried setting them and leaving them to their defaults.   I've even tried hard-coding them to the values I *know* are in the sample surface I'm looking at.  It makes no difference; The data looks great but the axis never shows me anything but the minimum value.   Again, this is what produces the attached image.

     

    <tk:RadCartesianChart3D x:Name="Chart"
                            FontSize="{Binding Settings.FontSizeMed}"
                            MouseDoubleClick="Chart_OnMouseDoubleClick"
                            >
        <tk:RadCartesianChart3D.Resources>
            <Style TargetType="{x:Type tk:LinearAxis3D}"
                   BasedOn="{StaticResource {x:Type tk:LinearAxis3D}}">
                <Setter Property="Visibility" Value="{Binding LocalSettings.SurfaceShowAxes, Converter={StaticResource BoolToVis}}"/>
            </Style>
        </tk:RadCartesianChart3D.Resources>
        <tk:RadCartesianChart3D.XAxis>
            <tk:LinearAxis3D Title="{Binding XAxisTitle}"
                             Minimum="{Binding XAxisMinLocal}"
                             LabelFormat="0.0"
                             SmartLabelsMode="SmartStep"
                             Maximum="{Binding XAxisMaxLocal}"
                             Foreground="GreenYellow"
                             >
                <tk:LinearAxis3D.LabelStyle>
                    <Style TargetType="TextBlock">
                        <Setter Property="Foreground" Value="GreenYellow"/>
                        <Setter Property="FontWeight" Value="Bold"/>
                    </Style>
                </tk:LinearAxis3D.LabelStyle>
            </tk:LinearAxis3D>
        </tk:RadCartesianChart3D.XAxis>
        <tk:RadCartesianChart3D.YAxis
            <tk:LinearAxis3D Title="{Binding YAxisTitle}"
                             Minimum="{Binding YAxisMinLocal}"
                             LabelFormat="0.0"
                             SmartLabelsMode="SmartStep"
                             Maximum="{Binding YAxisMaxLocal}"
                             Foreground="Orange"
                             >
                <tk:LinearAxis3D.LabelStyle>
                    <Style TargetType="TextBlock">
                        <Setter Property="Foreground" Value="Orange"/>
                        <Setter Property="FontWeight" Value="Bold"/>
                    </Style>
                </tk:LinearAxis3D.LabelStyle>
            </tk:LinearAxis3D>
        </tk:RadCartesianChart3D.YAxis>
     
        <tk:RadCartesianChart3D.ZAxis>
            <tk:LinearAxis3D Title="{Binding ZAxisTitle}"
                             LabelFormat="0.00"
                             SmartLabelsMode="SmartStep"
                             >
                <tk:LinearAxis3D.LabelStyle>
                    <Style TargetType="TextBlock">
                        <Setter Property="Foreground" Value="White"/>
                        <Setter Property="FontWeight" Value="Bold"/>
                    </Style>
                </tk:LinearAxis3D.LabelStyle>
            </tk:LinearAxis3D>
        </tk:RadCartesianChart3D.ZAxis>
     
        <tk:RadCartesianChart3D.Series>
     
            <tk:SurfaceSeries3D ItemsSource ="{Binding Points}"
                                XValueBinding="X"
                                YValueBinding="Y"
                                ZValueBinding="Z"
                                x:Name="Series"
                                >
     
                <tk:SurfaceSeries3D.Colorizer>
                    <tk:SurfaceSeries3DValueGradientColorizer x:Name="Colorizer"  IsAbsolute="True"/>
                </tk:SurfaceSeries3D.Colorizer>
            </tk:SurfaceSeries3D>
     
     
     
     
            <!--
            First cut at showing the profile line on the Surface display
            Still need to colorize it and to ensure that the points we get
            are NOT leveled because the Surface isn't...
            -->
            <!--
            <tk:LineSeries3D
                ItemsSource="{Binding ProfileLine, IsAsync=True}"
                XValueBinding="X"
                YValueBinding="Y"
                ZValueBinding="Z"
                x:Name="ProfileLine"
                DefaultLineVisualDiameter="8"
                Foreground="GreenYellow">
            </tk:LineSeries3D>
            -->
     
        </tk:RadCartesianChart3D.Series>
     
        <tk:RadCartesianChart3D.Grid>
            <tk:CartesianChart3DGrid XZGridLinesVisibility="All"
                                     YZGridLinesVisibility="All"
                                     XYGridLinesVisibility="All"
                                     Visibility="{Binding LocalSettings.SurfaceShowGridLines, Converter={StaticResource BoolToVis}}"/>
     
        </tk:RadCartesianChart3D.Grid>
     
        <!--
        JMO: Setting IsRotationEnabled to False would keep the 3d image
        fully illuminated no matter how you rotated it.
        -->
        <tk:RadCartesianChart3D.Lights>
            <DirectionalLight tk:Chart3DCameraBehavior.IsRotationEnabled="True"
                              Direction="0.0, 0.0 1.0"
                              />
        </tk:RadCartesianChart3D.Lights>
        <tk:RadCartesianChart3D.Behaviors>
            <tk:Chart3DCameraBehavior />
        </tk:RadCartesianChart3D.Behaviors>
     
    </tk:RadCartesianChart3D>

     

     

  4. Martin Ivanov
    Admin
    Martin Ivanov avatar
    2240 posts

    Posted 01 Jul Link to this post

    Hello Joe,

    Thank you for the provided information. I've tried your code, but I still cannot reproduce the issue. Can you please check the attached project and let me know if I am missing something?

    Regards,
    Martin Ivanov
    Progress Telerik
    Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
  5. Joe
    Joe avatar
    65 posts
    Member since:
    Nov 2017

    Posted 02 Jul in reply to Martin Ivanov Link to this post

    Hi Martin,

    I can produce the bug about it not showing the Maximum and minimum I want fairly easily.  Just go to the Z axis declaration in your example (the XAML element whose "x:Name" is set to "zAxis" and add attributes for Minimum and Maximum.  Here I've set it to -800 and positive 900.  So those are the number I expect to see on the top and bottom, right?

    <telerik:LinearAxis3D Title="{Binding ZAxisTitle}" x:Name="zAxis"
             LabelFormat="0.00"
             Minimum="-800"  Maximum="900"
             SmartLabelsMode="SmartStep"
             >

    If you do that, you won't see "900" at the top.  You'll see "700".  And it doesn't matter if you take out the "SmartLabelsMode" attribute.  It will still be  only 700.

    So how do I force it to use the number I specify for the max Z label?  

    Having said that, I will admit I unable to reproduce the second problem I see which only shows up in my production app.  The symptom (which ou can see it in the previous image I attached) is that I cannot make the Maximum label appear at all, no matter what I do.  I just get a Minimum label.  I'm not sure I can reproduce that one but I will try. 

    My hope is that whatever is preventing me from showing the label I want in *this* sample is causing my problems in my production app








  6. Answer
    Martin Ivanov
    Admin
    Martin Ivanov avatar
    2240 posts

    Posted 03 Jul Link to this post

    Hello Joe,

    Thank you for the clarification. Now I see what is the issue. The last tick and label are not shown because of the automatic tick step calculated by the axis. This step is calculated based on the applied minimum and maximum values. In your case, it is 500. And because the next number after 700 should be 1200 (700+500), but the maximum is 900, the last tick is not drawn. To resolve this, you can set the choose a custom step and assign it to the MajorStep property of the axis.
    <telerik:LinearAxis3D Title="{Binding ZAxisTitle}" x:Name="zAxis"
                          LabelFormat="0.00"
                          MajorStep="100"
                          Minimum="-800"  Maximum="900"
                          SmartLabelsMode="SmartStep">

    As for the second problem, if you succeed in reproducing it, you can post some steps here and I will investigate what could be happening.

    Regards,
    Martin Ivanov
    Progress Telerik
    Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
  7. Joe
    Joe avatar
    65 posts
    Member since:
    Nov 2017

    Posted 05 Jul in reply to Martin Ivanov Link to this post

    Hi Martin,

     

    I have managed to reproduce my issue with the axes refusing to show any Z values other than the bottom one.   However the only way I was able to reproduce it was to rewrite your sample along with some simplifed, file-reading code and use the actual data file that I use for my surface. 

    Unfortunately, that data file is 19 mb large.

    Is there some way I can get a file of that size to you for you to test with my modified sample?  I am guessing it's not going to let me attach something that large to the forum

  8. Joe
    Joe avatar
    65 posts
    Member since:
    Nov 2017

    Posted 05 Jul in reply to Joe Link to this post

    Actually, cancel that.  I am going to mark this as completely solved. 

    The work of reproducing my sample and comparing it to the original line-by-line finally made me stumble across the cause of the labels not showing at all.    It was all hidden in just one line in a code-behind handler (dating back to the first time I asked you a question about Surface Series, months ago). 

    I was doing work in a DataContextChanged handler and for some reason I can no-longer recall, I had a line in there which set the LabelInterval of the Z axis. 


            private void SurfaceDisplay_DataContextChanged(object sender, System.Windows.DependencyPropertyChangedEventArgs e)
            {

                 // Some other stuff that isn't relevant...

                 // ... etc etc.

     

                 // Now THIS LINE.  XAML bindings no longer matter...

                Chart.ZAxis.LabelInterval = 100;
            }


    This local, immediate value of course completely overwrote my XAML binding statement so it would not have mattered *what* I bound it to.   Hours and hours of frustration all due to a single line of code.  Once I removed that one line, it worked perfectly.

    Thank you for all your time.
  9. Martin Ivanov
    Admin
    Martin Ivanov avatar
    2240 posts

    Posted 10 Jul Link to this post

    Hello Joe,

    I am glad to hear that you managed to resolve the issue.

    Regards,
    Martin Ivanov
    Progress Telerik
    Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
Back to Top