Chart not updating?

Using a List with a Chart, and I am inserting new objects based off websocket activity. Adding new items into the list doesn't seem to force a chart update? I have tried calling chart.Reload() and nothing happens? What is the secret to getting the LineSeries to render in response to a data change?

EDIT: Also tried following chart.Reload with StateHasChanged...still no change in the chart....

EDIT2: So I am adding new objects to the list. My Category is datetime, do I have to do something to resize the axis? Or make the x-axis bigger manually?

EDIT3: So if I hide and show the chart each time the data is changed, it is redrawing with the new data...however it's flipped like 180 degrees and is upside down? Very strange behavior? But obviously the chart flickers....so that's not gonna work! I have also tried keeping 2 Lists and copying one to the other to trigger the chart to refresh, but that doesn't work either?

Thanks!

You have to update the value which their Data property is set to and then call the Reload method of the chart.

We would probably be more helpful if you provide some sample code that we can test with.

Ok, here's my code. The OnWSSEvent is an event that is fired when receiving data packets from a websocket connection. Just replace all that with a timer that generates new List objects to test with. I left some code out for clarity.

When I run this code, the chart never changes. If I preload objects in the "chartData" list, the chart does correctly display that data.

public class ChartDataItem
{
	public DateTime stamp { get; set; }
	public double cpuActive { get; set; }
}
public partial class StatusPage1Component : IDisposable
{
	public List<ChartDataItem> chartData = new List<ChartDataItem>();	
	
	void OnWSSEvent(object sender, Services.WSSEventArgs args)
	{
		if (args.me != null)
		{
			me = args.me;
			ChartDataItem d = new ChartDataItem() { stamp = DateTime.Now, cpuActive = me.DeviceStats.CpuActive };
			chartData.Add(d);
			if (chartData.Count > 100)
				chartData.RemoveAt(0);
			chart0.Reload();
		}
	}
}
	
<RadzenChart ColorScheme="ColorScheme.Pastel" @ref="chart0">
<ChildContent>
  <RadzenCategoryAxis FormatString="{0:mm.ss.ff}">
	<ChildContent>
	  <RadzenAxisTitle Text="Date">
	  </RadzenAxisTitle>
	</ChildContent>
  </RadzenCategoryAxis>
  <RadzenLineSeries CategoryProperty="stamp" Data="@chartData" Title="CPU Active" ValueProperty="cpuActive" @ref="series0">
	<ChildContent>
	  <RadzenMarkers MarkerType="MarkerType.Auto">
	  </RadzenMarkers>
	</ChildContent>
  </RadzenLineSeries>
  <RadzenValueAxis>
	<ChildContent>
	  <RadzenAxisTitle Text="Cpu Usage">
	  </RadzenAxisTitle>
	</ChildContent>
  </RadzenValueAxis>
</ChildContent>
</RadzenChart>

One thing...the show/hide did actually render the chart but it was flipped upsides down? So I know the chart does have the correct data internally. It seems some type of change handler is missing perhaps? I saw a demo of a pie chart that is pretty much identical to what I am trying to do. I wonder if that example would work as a Line Chart? I will try the pie chart.....

If this event executes outside of Blazor context you may have to use InvokeAsync to force an update. Also do chartData = chartData.ToList() this will update the Data property of the series and make it update. I agree this is not intuitive - we will add a check for the count of the Data property value to detect adding and removing items.

void OnWSSEvent(object sender, Services.WSSEventArgs args)
{
      if (args.me != null)
      {
         InvokeAsync(async () => 
         {
           me = args.me;
           ChartDataItem d = new ChartDataItem() { stamp = DateTime.Now, cpuActive = me.DeviceStats.CpuActive };
           chartData.Add(d);
           if (chartData.Count > 100)
               chartData.RemoveAt(0);
           chartData = chartData.ToList(); // Update the chartData reference
           await chart0.Reload();
          });
      }
}

Here is how this works with a timer:

And here is the sample page that I used to produce this animated gif:
linechart

@page "/line-chart"

<RadzenChart ColorScheme="ColorScheme.Pastel" @ref="chart0">
<ChildContent>
  <RadzenCategoryAxis FormatString="{0:mm.ss.ff}">
	<ChildContent>
	  <RadzenAxisTitle Text="Date">
	  </RadzenAxisTitle>
	</ChildContent>
  </RadzenCategoryAxis>
  <RadzenLineSeries CategoryProperty="stamp" Data="@chartData" Title="CPU Active" ValueProperty="cpuActive">
	<ChildContent>
	  <RadzenMarkers MarkerType="MarkerType.Auto">
	  </RadzenMarkers>
	</ChildContent>
  </RadzenLineSeries>
  <RadzenValueAxis>
	<ChildContent>
	  <RadzenAxisTitle Text="Cpu Usage">
	  </RadzenAxisTitle>
	</ChildContent>
  </RadzenValueAxis>
</ChildContent>
</RadzenChart>
@code {
public class ChartDataItem
{
	public DateTime stamp { get; set; }
	public double cpuActive { get; set; }
}
    RadzenChart chart0;
	public List<ChartDataItem> chartData = new List<ChartDataItem>();	

    protected override void OnInitialized()
    {
        System.Timers.Timer timer = new System.Timers.Timer();
        timer.Interval = 1000; // 3 secs in milliseconds
        timer.Elapsed += OnTimedEvent;
        timer.AutoReset = true;
        timer.Enabled = true;
    }

	void OnTimedEvent(object source, System.Timers.ElapsedEventArgs e)
	{
        InvokeAsync(async () =>
        {
            ChartDataItem d = new ChartDataItem() { stamp = DateTime.Now, cpuActive = new Random().NextDouble() * 1000 };
            chartData.Add(d);
            if (chartData.Count > 100)
                chartData.RemoveAt(0);
            chartData = chartData.ToList();
            await chart0.Reload();
        });
	}
}
1 Like

I tried the ToList before, but not while using InvokeAsync! So the only 2 changes to make my code work perfectly are these:

chartData = chartData.ToList();
InvokeAsync(() => { chart0.Reload(); });

and it works quite well! I did not see any chart examples or documentation where the InvokeAsync was used, so it didn't catch my attention, even though I am doing

InvokeAsync(() => { StateHasChanged(); });

all over the place to deal with other thread contexts!! I missed that one for the chart!!

You guys have quite good support on this forum I must say! Thank you so much for your time and help getting me going, it is MUCH appreciated!

EDIT: I actually tried this with just

chartData = chartData.ToList();

and it works fine, the Async Reload is NOT required! So the data change handler is evoked in the Blazor context, which is good. One thing...even if you add a "count" check for Data....eventually the list will fill to capacity and then the individual items will change, but the count will not. Could you perhaps do a hash on the IEnumerable list when the Data property is set and check it when a chart.Reload is performed??

Unfortunately adding items to List<T> does not seem to update the hashcode.

According to a forum post: The .GetHashCode() method usually just returns a hash based on the object reference (pointer address). This is because calculating the hash code of every item in an enumerable list can be very time intensive.

I would have thought that would have covered adding/removing, but it certainly won't help with edits....sigh....