Columns overlapping on DateTimeContinuousAxis

6 posts, 1 answers
  1. Mitchell
    Mitchell avatar
    45 posts
    Member since:
    Mar 2013

    Posted 12 Jan 2014 Link to this post

    I'm creating a column chart with the x axis as a DateTimeContinuousAxis. Once the date range reaches sufficient length, the column widths do not get any smaller. Instead, they start overlapping each other. In my case, I have a about 85 points over a period of about 8 months with the axis MajorStepUnit set to Days.  You can see in the first attachment, a screenshot of the chart where the column backgrounds are blue and the borders are red.  My expectation is that the column width should shrink as more columns are added & that there should be no overlapping.  Any guidance here would be appreciated. Thanks - Mitch.


    Below are the xaml and code behind for creating the attached screenshot (I can send the project if desired):



    XAML:



    <Window x:Class="MathNETTest.MainWindow"
            xmlns:local="clr-namespace:MathNETTest"
            Title="MainWindow" Height="750" Width="925" >
     
        <Window.Resources>
     
            <ResourceDictionary>
                <ResourceDictionary.MergedDictionaries>
                    <ResourceDictionary Source="pack://application:,,,/MathNETTest;component/Themes/Windows8/Telerik.Windows.Controls.xaml"/>
                    <ResourceDictionary Source="pack://application:,,,/MathNETTest;component/Themes/Windows8/Telerik.Windows.Controls.DataVisualization.xaml"/>
                    <ResourceDictionary Source="pack://application:,,,/MathNETTest;component/Themes/Windows8/Telerik.Windows.Controls.Chart.xaml"/>
                </ResourceDictionary.MergedDictionaries>
     
                <Style TargetType="{x:Type telerik:BarSeries}" BasedOn="{StaticResource BarSeriesStyle}">
                    <Setter Property="PointTemplate">
                        <Setter.Value>
                            <DataTemplate>
                                <Border Background="Blue" BorderBrush="Red" BorderThickness="1">                               
                                </Border>
                            </DataTemplate>
                        </Setter.Value>
                    </Setter>              
                </Style>
            </ResourceDictionary>
        </Window.Resources>
     
        <Grid>                     
            <telerik:RadCartesianChart x:Name="MyChart">
                 
                <telerik:RadCartesianChart.HorizontalAxis>
                    <telerik:DateTimeContinuousAxis LabelFitMode="Rotate"/>
     
                </telerik:RadCartesianChart.HorizontalAxis>
                 
                <telerik:RadCartesianChart.VerticalAxis>
                    <telerik:LinearAxis/>
                </telerik:RadCartesianChart.VerticalAxis>
     
                <telerik:RadCartesianChart.Grid>
                    <telerik:CartesianChartGrid MajorLinesVisibility="XY">
     
                        <telerik:CartesianChartGrid.MajorXLineStyle>
                            <Style TargetType="Line">
                                <Setter Property="Stroke" Value="Black"/>                              
                            </Style>
                        </telerik:CartesianChartGrid.MajorXLineStyle>
     
                        <telerik:CartesianChartGrid.MajorYLineStyle>
                            <Style TargetType="Line">
                                <Setter Property="Stroke" Value="Black"/>                           
                            </Style>
                        </telerik:CartesianChartGrid.MajorYLineStyle>
     
                    </telerik:CartesianChartGrid>
                </telerik:RadCartesianChart.Grid>
     
            </telerik:RadCartesianChart>
        </Grid>
    </Window>




    Code behind:



    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.ComponentModel;
    using System.Numerics;
    using Telerik.Windows.Controls.ChartView;
     
    namespace MathNETTest
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            public ObservableCollection<MySeries> Series { get; set; } 
            public ChartSeriesProvider SeriesProvider { get; set; }
     
            public MainWindow()
            {
                InitializeComponent();
                this.DataContext = this;
     
                ObservableCollection<MyPoint> points = new ObservableCollection<MyPoint>();
                MyPoint p = new MyPoint(new DateTime(2012, 9, 2), 4); points.Add(p);
                p = new MyPoint(new DateTime(2012, 9, 3), 6); points.Add(p);
                p = new MyPoint(new DateTime(2012, 9, 4), 4); points.Add(p);
                p = new MyPoint(new DateTime(2012, 9, 5), 3); points.Add(p);
                p = new MyPoint(new DateTime(2012, 9, 6), 1); points.Add(p);
                p = new MyPoint(new DateTime(2012, 9, 30), 3); points.Add(p);
                p = new MyPoint(new DateTime(2012, 10, 1), 1); points.Add(p);
                p = new MyPoint(new DateTime(2012, 10, 2), 2); points.Add(p);
                p = new MyPoint(new DateTime(2012, 10, 3), 3); points.Add(p);
                p = new MyPoint(new DateTime(2012, 10, 4), 1); points.Add(p);
                p = new MyPoint(new DateTime(2012, 10, 28), 4); points.Add(p);
                p = new MyPoint(new DateTime(2012, 10, 29), 2); points.Add(p);
                p = new MyPoint(new DateTime(2012, 11, 25), 2); points.Add(p);
                p = new MyPoint(new DateTime(2012, 12, 30), 5); points.Add(p);
                p = new MyPoint(new DateTime(2012, 12, 31), 1); points.Add(p);
                p = new MyPoint(new DateTime(2013, 1, 1), 2); points.Add(p);
                p = new MyPoint(new DateTime(2013, 1, 2), 3); points.Add(p);
                p = new MyPoint(new DateTime(2013, 1, 3), 1); points.Add(p);
                p = new MyPoint(new DateTime(2013, 1, 7), 2); points.Add(p);
                p = new MyPoint(new DateTime(2013, 1, 8), 2); points.Add(p);
                p = new MyPoint(new DateTime(2013, 1, 9), 3); points.Add(p);
                p = new MyPoint(new DateTime(2013, 1, 10), 2); points.Add(p);
                p = new MyPoint(new DateTime(2013, 1, 13), 3); points.Add(p);
                p = new MyPoint(new DateTime(2013, 1, 14), 14); points.Add(p);
                p = new MyPoint(new DateTime(2013, 1, 15), 6); points.Add(p);
                p = new MyPoint(new DateTime(2013, 1, 16), 9); points.Add(p);
                p = new MyPoint(new DateTime(2013, 1, 17), 5); points.Add(p);
                p = new MyPoint(new DateTime(2013, 1, 20), 4); points.Add(p);
                p = new MyPoint(new DateTime(2013, 1, 21), 6); points.Add(p);
                p = new MyPoint(new DateTime(2013, 1, 22), 6); points.Add(p);
                p = new MyPoint(new DateTime(2013, 1, 23), 8); points.Add(p);
                p = new MyPoint(new DateTime(2013, 1, 24), 4); points.Add(p);
                p = new MyPoint(new DateTime(2013, 1, 28), 4); points.Add(p);
                p = new MyPoint(new DateTime(2013, 1, 29), 20); points.Add(p);
                p = new MyPoint(new DateTime(2013, 1, 30), 17); points.Add(p);
                p = new MyPoint(new DateTime(2013, 1, 31), 4); points.Add(p);
                p = new MyPoint(new DateTime(2013, 2, 3), 2); points.Add(p);
                p = new MyPoint(new DateTime(2013, 2, 4), 15); points.Add(p);
                p = new MyPoint(new DateTime(2013, 2, 5), 7); points.Add(p);
                p = new MyPoint(new DateTime(2013, 2, 6), 10); points.Add(p);
                p = new MyPoint(new DateTime(2013, 2, 7), 10); points.Add(p);
                p = new MyPoint(new DateTime(2013, 2, 8), 1); points.Add(p);
                p = new MyPoint(new DateTime(2013, 2, 11), 6); points.Add(p);
                p = new MyPoint(new DateTime(2013, 2, 12), 6); points.Add(p);
                p = new MyPoint(new DateTime(2013, 2, 13), 9); points.Add(p);
                p = new MyPoint(new DateTime(2013, 2, 14), 6); points.Add(p);
                p = new MyPoint(new DateTime(2013, 2, 17), 4); points.Add(p);
                p = new MyPoint(new DateTime(2013, 2, 18), 9); points.Add(p);
                p = new MyPoint(new DateTime(2013, 2, 19), 5); points.Add(p);
                p = new MyPoint(new DateTime(2013, 2, 20), 4); points.Add(p);
                p = new MyPoint(new DateTime(2013, 2, 21), 4); points.Add(p);
                p = new MyPoint(new DateTime(2013, 2, 22), 1); points.Add(p);
                p = new MyPoint(new DateTime(2013, 2, 24), 1); points.Add(p);
                p = new MyPoint(new DateTime(2013, 2, 25), 11); points.Add(p);
                p = new MyPoint(new DateTime(2013, 2, 26), 7); points.Add(p);
                p = new MyPoint(new DateTime(2013, 2, 27), 8); points.Add(p);
                p = new MyPoint(new DateTime(2013, 2, 28), 8); points.Add(p);
                p = new MyPoint(new DateTime(2013, 3, 1), 6); points.Add(p);
                p = new MyPoint(new DateTime(2013, 3, 3), 1); points.Add(p);
                p = new MyPoint(new DateTime(2013, 3, 4), 13); points.Add(p);
                p = new MyPoint(new DateTime(2013, 3, 5), 11); points.Add(p);
                p = new MyPoint(new DateTime(2013, 3, 6), 10); points.Add(p);
                p = new MyPoint(new DateTime(2013, 3, 7), 11); points.Add(p);
                p = new MyPoint(new DateTime(2013, 3, 8), 5); points.Add(p);
                p = new MyPoint(new DateTime(2013, 3, 10), 1); points.Add(p);
                p = new MyPoint(new DateTime(2013, 3, 11), 2); points.Add(p);
                p = new MyPoint(new DateTime(2013, 3, 12), 4); points.Add(p);
                p = new MyPoint(new DateTime(2013, 3, 13), 6); points.Add(p);
                p = new MyPoint(new DateTime(2013, 3, 14), 4); points.Add(p);
                p = new MyPoint(new DateTime(2013, 3, 15), 11); points.Add(p);
                p = new MyPoint(new DateTime(2013, 3, 16), 10); points.Add(p);
                p = new MyPoint(new DateTime(2013, 3, 17), 8); points.Add(p);
                p = new MyPoint(new DateTime(2013, 3, 18), 5); points.Add(p);
                p = new MyPoint(new DateTime(2013, 3, 19), 4); points.Add(p);
                p = new MyPoint(new DateTime(2013, 3, 20), 7); points.Add(p);
                p = new MyPoint(new DateTime(2013, 3, 21), 3); points.Add(p);
                p = new MyPoint(new DateTime(2013, 3, 23), 1); points.Add(p);
                p = new MyPoint(new DateTime(2013, 3, 25), 4); points.Add(p);
                p = new MyPoint(new DateTime(2013, 3, 26), 2); points.Add(p);
                p = new MyPoint(new DateTime(2013, 3, 27), 1); points.Add(p);
                p = new MyPoint(new DateTime(2013, 3, 28), 1); points.Add(p);
                p = new MyPoint(new DateTime(2013, 4, 9), 2); points.Add(p);
                p = new MyPoint(new DateTime(2013, 4, 18), 1); points.Add(p);
                p = new MyPoint(new DateTime(2013, 5, 20), 1); points.Add(p);
     
                this.Series = new ObservableCollection<MySeries>();
                MySeries series = new MySeries();
                series.Points = points;
                this.Series.Add(series);
     
                this.SeriesProvider = new ChartSeriesProvider();
                this.SeriesProvider.Source = this.Series;
     
                CategoricalSeriesDescriptor sd = new CategoricalSeriesDescriptor();
                sd.CategoryPath = "X";
                sd.ValuePath = "Y";
                sd.ItemsSourcePath = "Points";
                sd.CollectionIndex = 0;
                sd.TypePath = "TelerikSeriesType";
     
                this.SeriesProvider.SeriesDescriptors.Add(sd);
     
                this.MyChart.SeriesProvider = this.SeriesProvider;
            }
        }
     
        public class MySeries
        {
            public MySeries()
            {
                this.TelerikSeriesType = typeof(BarSeries);
            }
            public SolidColorBrush Color { get; set; }
            public ObservableCollection<MyPoint> Points { get; set; }
     
            public Type TelerikSeriesType{get; set;}
        }
     
        public class MyPoint
        {
            public MyPoint(DateTime x, double y)
            {
                X = x;
                Y = y;
            }
     
            public DateTime X { get; set; }
            public double Y { get; set; }
        }
    }




  2. Yavor
    Admin
    Yavor avatar
    401 posts

    Posted 15 Jan 2014 Link to this post

    Hello Mitchell,

    The DateTimeContinuous axis is a continuous axis, which works very similar to a linear axis. This means that it creates the slots for your items based on the date time range and some major step, which can be calculated automatically or specified manually. Be default if the major step is not specified, the axis will try to come up with a step that will allow your axis to show a reasonable amount of major ticks (and labels). But in your scenario you are using bars and you have some clustered data points - some are close together, others are some distance away. In this scenario it is best if you choose the granularity of the axis yourself. If you know that the granularity for your data is day, you can adjust the slots for your bars by specifying the MajorStep and MajorStepUnit like this:

    <telerik:DateTimeContinuousAxis MajorStep="1" MajorStepUnit="Day" />

    It is important to choose the correct major step and major step unit for your scenario. Too fine grained and you will end up having too thin bars and lots of labels and ticks. Too coarse grained and your bars will start to overlap. So choosing the correct ones depends on your data.

    If you end up having more labels than you want there are several way in which you can reduce them:
    1) First you can try setting LabelInterval, which defines the step at which labels are positioned;
    2) Another option is to use shorter format, which is defined in LabelFormat property;
    3) Also it is possible to rotate the labels a bit so that they don't overlap. This is done via the combination of these 2 properties: LabelFitMode="Rotate" LabelRotationAngle="{angle}";
    4) Yet another option could be to place the labels on multiple rows. This can be set with this property: LabelFitMode="MultiLine";

    All these properties control only the labels of your axis. The ticks will not be changed in any way and your bars will be displayed properly. So my advice is to configure the axis to show your bars correctly using the MajorStepUnit and MajorStep properties, then use one or several of the approaches described above to reduce the number of labels in your axis.

    Regards,
    Yavor
    Telerik
    TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for WPF.
    Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
    Sign up for Free application insights >>
  3. UI for WPF is Visual Studio 2017 Ready
  4. Mitchell
    Mitchell avatar
    45 posts
    Member since:
    Mar 2013

    Posted 15 Jan 2014 Link to this post

    I've "solved" my issue using Reflection on the cartesian grid.  So, certainly not a recommended way of doing things since any version upgrade could invalidate this method. However, for academic purposes, here's what can be done to make gridlines without an associated label transparent:

    private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                SolidColorBrush transparentBrush = new SolidColorBrush(Colors.Transparent);
     
                //Do some funky reflection to hide tick marks that don't have a label
                FieldInfo majorXLinesFieldInfo = this.MyGrid.GetType().GetField("majorXLines", BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.Instance);
                if (null != majorXLinesFieldInfo)
                {
                    //GridLinesInfo is a private class
                    var majorXLines = majorXLinesFieldInfo.GetValue(this.MyGrid);
     
                    FieldInfo linePresentersInfo = majorXLines.GetType().GetField("LinePresenters");
                    FieldInfo linesInfo = majorXLines.GetType().GetField("Lines");
                    if (null != linePresentersInfo && null != linesInfo)
                    {
                        var linePresenters = linePresentersInfo.GetValue(majorXLines);
                        var lines = linesInfo.GetValue(majorXLines);
                        int i = 0;
                        foreach (var line in (IEnumerable)linePresenters)
                        {
                            var gridLine = ((IList)lines)[i];
     
                            FieldInfo associatedTickFieldInfo = gridLine.GetType().GetField("AssociatedTick");
                            if (null != associatedTickFieldInfo)
                            {
                                var associatedTick = associatedTickFieldInfo.GetValue(gridLine);
     
                                FieldInfo associatedLabelInfo = associatedTick.GetType().GetField("associatedLabel", BindingFlags.Instance | BindingFlags.NonPublic);
                                if (null != associatedLabelInfo)
                                {
                                    var associatedLabel = associatedLabelInfo.GetValue(associatedTick);
                                    if (null == associatedLabel)
                                    {
                                         
                                        ((Line)line).Stroke = transparentBrush;
                                        ((Line)line).Fill = transparentBrush;
     
                                    }                              
                                }
                            }
     
                            i++;
                        }
                    }              
                }
            }
  5. Yavor
    Admin
    Yavor avatar
    401 posts

    Posted 20 Jan 2014 Link to this post

    Hi Mitchell,

    So your problem is how to hide the grid lines that don't have an associated label, is it? I didn't understand that from your initial post.

    Regards,
    Yavor
    Telerik
    TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for WPF.
    Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
    Sign up for Free application insights >>
  6. Mitchell
    Mitchell avatar
    45 posts
    Member since:
    Mar 2013

    Posted 20 Jan 2014 Link to this post

    That's basically it. I wanted a fairly small number of grid lines (all with labels). 5-10 depending on the width of the chart. I could achieve that by setting the major tick step, but that resulted in the overlapping columns because the column width grew with those settings. I needed the columns to stay the width of "1 day".
  7. Answer
    Yavor
    Admin
    Yavor avatar
    401 posts

    Posted 21 Jan 2014 Link to this post

    Hello Mitchell,

    I can confirm we have identified this limitation of the chartview grid and will look into it. A better approach for your scenario would be to use custom grid line annotations instead. This way you can display grid lines exactly where you need them. Documentation of annotations can be found here.

    Regards,
    Yavor
    Telerik
    TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for WPF.
    Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
    Sign up for Free application insights >>
Back to Top
UI for WPF is Visual Studio 2017 Ready