7

I recently encountered a tool called LiveChart and decided to test it out.

Unfortunately I've been having some problems figuring out how to update the chart values in real time. I'm pretty sure there's a clean and correct way of doing it, but I can't seam to find it.

I would like to be able to update the values through a private void or button.

In my code I'm testing it out with a ToolStripMenu.

[CODE]:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using LiveCharts;
using LiveCharts.WinForms;
using LiveCharts.Wpf;
using PokeShowdown_AccStats_T.Properties;
using LiveCharts.Defaults;

namespace PokeShowdown_AccStats_T
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            //int val1 = int.Parse(Settings.Default.Value1);

            var value1 = new ObservableValue(3);
            var value2 = new ObservableValue(7);
            var value3 = new ObservableValue(10);
            var value4 = new ObservableValue(2);

            //value1.Value = 5;

            cartesianChart1.Series.Add(new LineSeries 
            {
                Values = new ChartValues<ObservableValue> { value1, value2, value3, value4 },
                StrokeThickness = 4,
                StrokeDashArray = new System.Windows.Media.DoubleCollection(20),
                Stroke = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Color.FromRgb(107, 185, 69)),
                Fill = System.Windows.Media.Brushes.Transparent,
                LineSmoothness = 0,
                PointGeometry = null
            });



            cartesianChart1.Background = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Color.FromRgb(34, 46, 49));

            cartesianChart1.AxisX.Add(new Axis
            {
                IsMerged = true,
                Separator = new Separator
                {
                    StrokeThickness = 1,
                    StrokeDashArray = new System.Windows.Media.DoubleCollection(2),
                    Stroke = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Color.FromRgb(64, 79, 86))
                }
            });
            cartesianChart1.AxisY.Add(new Axis
            {
                IsMerged = true,
                Separator = new Separator
                {
                    StrokeThickness = 1.5,
                    StrokeDashArray = new System.Windows.Media.DoubleCollection(4),
                    Stroke = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Color.FromRgb(64, 79, 86))
                }
            });
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void changeValue1ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Settings.Default.Value1 = "10";
            Settings.Default.Save();
            this.Text = Settings.Default.Value1;

        }

        private void changeValue1To3ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Settings.Default.Value1 = "3";
            Settings.Default.Save();
            this.Text = Settings.Default.Value1;

        }
    }
}
bto.rdz
  • 6,636
  • 4
  • 35
  • 52
Jose Cancel
  • 151
  • 1
  • 2
  • 15

3 Answers3

9

Live-Charts tries to keep it simple. The logic is to use a generic collection with the type you need to plot, and then as easy as adding/removing or updating any element in this collection then your chart will be updated.

To answer your question, you normally need to:

public partial class Form1 : Form
{
    private ObservableValue value1;

    public Form1()
    {
        InitializeComponent();

        //int val1 = int.Parse(Settings.Default.Value1);

        value1 = new ObservableValue(3);
        //...

        cartesianChart1.Series.Add(new LineSeries 
        {
            Values = new ChartValues<ObservableValue> { value1, ... },
        });
    }

    private void changeValue1ToolStripMenuItem_Click(object sender, EventArgs e)
    {
        value1.Value = 10;
        Settings.Default.Value1 = "10";
        Settings.Default.Save();
        this.Text = Settings.Default.Value1;

    }
}

Then the library will handle animations and the update

enter image description here

Jose Cancel
  • 151
  • 1
  • 2
  • 15
bto.rdz
  • 6,636
  • 4
  • 35
  • 52
  • I know this is old but is there any way you can share the logic/code for add, insert, remove, and move all buttons? I have been trying to figure how to implement these but LiveCharts documentation only shows how to update the Values variable for a Series by replacing the entire Values variable with another ChartValues variable which ends up redrawing the entire chart. – Ahmed Khan May 13 '22 at 20:47
4

Note: The question is about LiveCharts. But this answer is posted based on MSChart. To see the answer about LiveCharts see other answer.

Chart supports data-binding. Use data-binding and update data source then refresh chart. For example:

DataTable table = new DataTable();
Random random = new Random();
private void Form1_Load(object sender, EventArgs e)
{
    table.Columns.Add("X", typeof(int));
    table.Columns.Add("Y", typeof(int));
    for (int i = 0; i < 10; i++)
        table.Rows.Add(i+1, random.Next(100));
    chart1.Series[0].ChartType = 
        System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Column;
    chart1.Series[0].XValueMember = "X";
    chart1.Series[0].YValueMembers = "Y";
    chart1.DataSource = table;
    chart1.ChartAreas[0].AxisX.Interval = 1;
    chart1.ChartAreas[0].AxisX.Minimum = 0;
    chart1.ChartAreas[0].AxisX.Maximum = 10;
    chart1.ChartAreas[0].AxisY.Interval = 10;
    chart1.ChartAreas[0].AxisY.Minimum = 0;
    chart1.ChartAreas[0].AxisY.Maximum = 100;
    chart1.DataBind();
    var timer = new Timer() { Interval= 300};
    timer.Tick += timer_Tick;
    timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{
    for (int i = 0; i < 10; i++)
        table.Rows[i][1]= random.Next(100);
    chart1.DataBind();
}

enter image description here

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
  • This is not what the OP is asking, he is asking abut Live-Charts – bto.rdz Nov 04 '16 at 15:45
  • @bto.rdz It seems I missed and mistakenly removed livecharts tag in edit. Yes the question is about livecharts. – Reza Aghaei Nov 04 '16 at 16:50
  • @bto Also you/other anyone who downvoted the answer don't need donwvote an answer just to fade it. This post will be useful for future readers who wants to do the trick using mschart. You can post a good answer instead, no need to fade other answers. – Reza Aghaei Nov 04 '16 at 16:51
  • Sorry, I wanted to remove the down vote, but it was too late, I know your answer is also helpful – bto.rdz Nov 04 '16 at 16:53
  • @bto.rdz No problem. I edited the answer and you can do it now. – Reza Aghaei Nov 04 '16 at 16:55
0

Hi for Pie chart you can upload the value in this easy way:

code Behind:

/// <summary>
/// Interaction logic for StatusChart.xaml
/// </summary>
public partial class StatusChart : UserControl
{
    #region - Values -
    private List<Double> values;
    public List<Double> Values
    {
         
        get => values;
        set
        {
            if (value is null) throw new NullReferenceException();
            if (value.Count > PieChart.Series.Count) throw new IndexOutOfRangeException();

            for(int serie = 0; serie < PieChart.Series.Count; serie++)
            {
                PieChart.Series[serie].ActualValues[0] = values[serie];
            }

            PieChart.Series.ForEach((i, s) => s.ActualValues[0] = value[i]);
        }
    }
    #endregion
    public StatusChart()
    {
        InitializeComponent();
        
        values = Enumerable.Repeat(1D, PieChart.Series.Count).ToList();
        
        PointLabel = chartPoint => string.Format(new CultureInfo("en-US"), "{0:#0}s", chartPoint.Y);

        GridRoot.DataContext = this;
    }
    public Func<ChartPoint, string> PointLabel { get; set; }

    /// <summary>
    /// method to enalrge the slice (part of pie chart) 
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="chartpoint"></param>
    private void Chart_OnDataClick(object sender, ChartPoint chartpoint)
    {
        var chart = (LiveCharts.Wpf.PieChart)chartpoint.ChartView;

        //clear selected slice.
        foreach (PieSeries series in chart.Series)
            series.PushOut = 0;

        var selectedSeries = (PieSeries)chartpoint.SeriesView;
        selectedSeries.PushOut = 7;
    }             
}

and xaml code:

<UserControl x:Class="StatusChart"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="500"
         d:DataContext="{d:DesignInstance local:StatusChart}">

<Grid x:Name="GridRoot">
    <lvc:PieChart x:Name="PieChart" LegendLocation="Bottom" DataClick="Chart_OnDataClick" Hoverable="False"><!-- DataTooltip="{x:Null}">-->
        <lvc:PieChart.Series>
            
            <lvc:PieSeries Title="serie1" 
                           Values="1" DataLabels="True" LabelPoint="{Binding PointLabel}">
            </lvc:PieSeries>

            <lvc:PieSeries Title="serie2" 
                           Values="1" DataLabels="True" LabelPoint="{Binding PointLabel}">
            </lvc:PieSeries>

            <lvc:PieSeries Title="serie3" Values="1" DataLabels="True" 
                           LabelPoint="{Binding PointLabel}"/>

            <lvc:PieSeries Title="serie4" Values="1" DataLabels="True" 
                           LabelPoint="{Binding PointLabel}">
            </lvc:PieSeries>

            <lvc:PieSeries Title="serie4" Values="1" DataLabels="True" 
                           LabelPoint="{Binding PointLabel}">
            </lvc:PieSeries>
        </lvc:PieChart.Series>            
    </lvc:PieChart>
</Grid>

and just to try the control in a window wpf test put this few lines:

 var temporalSc = Enumerable.Repeat(1D, StatusChart.PieChart.Series.Count).ToList();
            for (var i = 0; i < StatusChart.PieChart.Series.Count; i++)
            {
                temporalSc[i] += rnd.Next(1, 87);
            }

            StatusChart.Values.Clear();
            StatusChart.Values = temporalSc;
luka
  • 605
  • 8
  • 15