Search code examples
c#xamllivecharts

How do i get X Axis to start from 0 and update each second instead of using the current time(DateTime)?


I'm trying to create like a measuring system that can measure a value on Y axis and time on X axis with LiveCharts.

I've used Constant Changes as a base to create my graph but I want my X Axis to start from 0 seconds instead of the current time like they do in the example. I've tried How to make the x Axis to start on 0 and have a step of 2 seconds, instead of staring on a second the program started, using Livecharts? but I couldn't get it to work with my program. I want to do the same thing they did in thread linked above but can't get it to work.

My Output/ How it looks

Code Behind:

        public void init()
        {
            var mapper = Mappers.Xy<ValueRandomizerForTest>().X(model => 
             model.DateTime.Ticks).Y(model => model.Valuefordate);
            Charting.For<ValueRandomizerForTest>(mapper);
            ChartValues = new ChartValues<ValueRandomizerForTest>();
            DateTimeFormatter = value => new 
                 DateTime((long)value).ToString("ss");
            AxisStep = TimeSpan.FromSeconds(1).Ticks;

            AxisUnit = TimeSpan.TicksPerSecond;
            SetAxisLimits(DateTime.Now);


        }


public void read()
        {


            var r = new Random();

            while (isreading)
            {
                Thread.Sleep(550);
                var now = DateTime.Now;
                var test = now.Second;


                _trend = r.Next(1, 100);

                if(ChartValues.Count == 0)
                {


                }

                ChartValues.Add(new ValueRandomizerForTest
                {
                    DateTime = now,
                    Valuefordate = _trend
                });


                SetAxisLimits(now);

                //lets only use the last 150 values
                if (ChartValues.Count > 150)
                {
                    ChartValues.RemoveAt(0);
                }
            }



        }
        public void SetAxisLimits(DateTime now)
        {

            AxisMax = now.Ticks + TimeSpan.FromSeconds(1).Ticks; //Axis is moving 1 second ahead
            AxisMin = now.Ticks - TimeSpan.FromSeconds(5).Ticks; 
        }

ValuerandomizerFortest Class:

        public DateTime DateTime { get; set; }
        public TimeSpan Time { get; set; }
        public double Valuefordate { get; set; }



        public double AxisStep { get; set; }

        public double AxisUnit { get; set; }


           private double _axisMax;

           private double _axisMin;


        public double AxisMax
        {

            get
            {
                return _axisMax
            }

            set
            {
                _axisMax = value;
                NotifyPropertyChanged("AxisMax");
            }
        }
        public double AxisMin
        {
            get { return _axisMin; }
            set
            {
                _axisMin = value;
                NotifyPropertyChanged("AxisMin");
            }
        }

XAML:

<Window x:Class="WPFDemo.Views.GraphViewer"
        xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WPFDemo.Views"
        mc:Ignorable="d"
        Title="GraphViewer" Height="700" Width="950">
    <Grid >
        <Grid Margin="759,10,10,588.4" RenderTransformOrigin="0.51,0.526">
            <Button Content="Random"
                Margin="6"
                Padding="6"
                Command="{Binding randomer}">

            </Button>

        </Grid>
        <!--<Grid Height="80" Width="200" Margin="50, -20,600,500">
            -->
        <!--<ComboBox ItemsSource="{Binding list}" Margin="-32,-10,32,20">
                -->
        <!--<ComboBox.ItemTemplate>
                    -->
        <!--<DataTemplate>
                        <TextBlock Text="{Binding Name}">

                        </TextBlock>
                    </DataTemplate>-->
        <!--
                </ComboBox.ItemTemplate>-->
        <!--
            </ComboBox>-->

        <!--<Button Content="Updater"
                    Command="{Binding ClickCommand}">


            </Button>-->
        <!--

        </Grid>-->
        <Grid Height="500" Width="940" Margin="4,100,0,28.4">



            <lvc:CartesianChart Grid.Row="1" AnimationsSpeed="0:0:0.3" Hoverable="False" DataTooltip="{x:Null}">
                <lvc:CartesianChart.Series>
                    <lvc:LineSeries Values="{Binding ChartValues}" 
                                PointGeometry="{x:Null}" 
                                LineSmoothness="1"
                                StrokeThickness="6" 
                                Stroke="#F34336"
                                Fill="Transparent"/>
                </lvc:CartesianChart.Series>
                <lvc:CartesianChart.AxisX>
                    <lvc:Axis x:Name="XAxis" LabelFormatter="{Binding DateTimeFormatter}" 
                          MaxValue="{Binding AxisMax}" 
                          MinValue="{Binding AxisMin}"
                          Unit="{Binding AxisUnit}">
                        <lvc:Axis.Separator>
                            <lvc:Separator Step="{Binding AxisStep}" />
                        </lvc:Axis.Separator>
                    </lvc:Axis>
                </lvc:CartesianChart.AxisX>
            </lvc:CartesianChart>

        </Grid>
    </Grid>
</Window>

Solution

  • See comments inline:

        private long startTimeTicks;
        public void init()
        {
            var mapper = Mappers.Xy<ValueRandomizerForTest>().X(model => 
             model.DateTime.Ticks).Y(model => model.Valuefordate);
            Charting.For<ValueRandomizerForTest>(mapper);
            ChartValues = new ChartValues<ValueRandomizerForTest>();
            DateTimeFormatter = value => new 
                 DateTime((long)value).ToString("ss");
            AxisStep = TimeSpan.FromSeconds(1).Ticks;
    
            AxisUnit = TimeSpan.TicksPerSecond;
    
            var currentTime = DateTime.Now;
            startTimeTicks = currentTime.Ticks; // store start time
            SetAxisLimits(currentTime);
        }
    
        public void read()
        {
            var r = new Random();
    
            while (isreading)
            {
                Thread.Sleep(550);
                var now = DateTime.Now;
                var test = now.Second;
    
                _trend = r.Next(1, 100);
    
                if(ChartValues.Count == 0)
                {
                }
    
                ChartValues.Add(new ValueRandomizerForTest
                {
                    DateTime = now - new TimeSpan(startTimeTicks),
                    Valuefordate = _trend
                });
    
                SetAxisLimits(now);
    
                //lets only use the last 150 values
                if (ChartValues.Count > 150)
                {
                    ChartValues.RemoveAt(0);
                }
            }
        }
    
        public void SetAxisLimits(DateTime now)
        {
            long offsetTicks = now.Ticks - startTimeTicks; // compute offset ticks from program start (at call from init() this calculation will be equal to 0)
            AxisMin = Math.Max(offsetTicks - TimeSpan.FromSeconds(5).Ticks, 0);
            AxisMax = AxisMin  + TimeSpan.FromSeconds(6).Ticks; // Set max according to min
        }