Issue adding to Series Line Chart with Foreach

Firstly, Iet me start by saying I am completely new to C# and Blazor and this is my first project using the language and tools so I am learning as I go.
I am currently trying to use RadzenLineSeries to display Disk Usage (%).
If I choose to display a single disk, I have no issues.

<RadzenLineSeries Smooth="false" Data="@Disk_Stats" CategoryProperty="Date" Title="Used" LineType="LineType.Dashed" ValueProperty="Used_PC">
    <RadzenMarkers Visible="@showMarkers" MarkerType="MarkerType.Square" />
    <RadzenSeriesDataLabels Visible="false" />
</RadzenLineSeries>

However when trying to add multiple disks using a foreach loop, the properties then require me to convert the values to string. The Category value is Date and value property is a decimal.

<RadzenChart @ref="DiskStats" Style="width:100%;">
    <RadzenChartTooltipOptions Shared="true" />
             @foreach (var D in Disk_Stats) 
             {    
                    string dDate = @D.Date.ToString();
                    <RadzenLineSeries Smooth="false" Data="@Disk_Stats" 
                      CategoryProperty="@D.Date" Title="@D.Disk_ID" 
                      LineType="LineType.Dashed" ValueProperty="Used_PC">

                              <RadzenMarkers Visible="@showMarkers" 
                                MarkerType="MarkerType.Auto" />
                                          <RadzenSeriesDataLabels Visible="false" />
                   </RadzenLineSeries>
               }   
    <RadzenCategoryAxis FormatString="{0:g}" Step="5">
        <RadzenTicks>
            <Template>
                <text class="rz-tick-text" style=" text-anchor: start; transform:  
                 translate(@(context.X)px, @(context.Y + 10)px) 
                 rotate(45deg)">@context.Value</text>
            </Template>
        </RadzenTicks>
    </RadzenCategoryAxis>
    <RadzenValueAxis Min="0" Max="100" Step="10">
        <RadzenGridLines Visible="true" />
        <RadzenAxisTitle Text="Utilisation (%)" />
    </RadzenValueAxis>
</RadzenChart>

This doesn't show any errors in visual studio however once I then run the application and load the page.... I get a runtime error in Dev Tools...

*Error: System.ArgumentException: Property 09/21/2024 16:45:07 does not exist*
*   at Radzen.Blazor.CartesianSeries`1.IsDate(String propertyName)*
*   at Radzen.Blazor.CartesianSeries`1.SetParametersAsync(ParameterView parameters)*

Each Disks values are recorded in SQL at the same time and all have the same datetime value for each interval.

Please can someone advise?

p.s apologies for the formatting... not sure what went wrong?

Hi @n0bby,

This seems to be the problem. CategoryProperty should be set to the name of the property not a concrete value e.g. CategoryProperty="Date"

You can check the FAQ

for tips how to format code.

Thanks for the reply.

If I remove "@D." the page loads however the chart does not display any data?

I suggest trying to reproduce the problem in our online demos (they are editable). Then we can see what the problem is. Right now we can't tell what is wrong just from looking at a screenshot.

Are you able to explain the exception to me please? I don't understand why it states the property does not exist?

blazor.server.js:1  [2024-09-22T11:18:08.558Z] Error: System.ArgumentException: Property 21/09/2024 16:45:07 does not exist
   at Radzen.Blazor.CartesianSeries`1.IsDate(String propertyName)
   at Radzen.Blazor.CartesianSeries`1.SetParametersAsync(ParameterView parameters)

Hi @n0bby

Without knowing your data structure, I can't be sure, but shouldn't the Data of your <RadzenLineSeries> be @D instead of @Disk_Stats?

Regards

Paul

If I user Data=@D It doesn't like it for some reason?

  public class DiskModel
  {
      public string Server { get; set; }
      public string Disk_ID { get; set; }
      public decimal Capacity { get; set; }
      public decimal Free { get; set; }
      public decimal Used { get; set; }
      public decimal Free_PC { get; set; }
      public decimal Used_PC { get; set; }
      public DateTime Date { get; set; }
  }
 private List<DiskModel> Disk_Stats;

 protected override async Task OnInitializedAsync()
  {

      Disk_Stats = await _db.GetServerDiskUsage(Server, period);
  }
public Task<List<DiskModel>> GetServerDiskUsage(string server, int period)
{
    string sql = "Select d.Server, du.[Date], d.Disk_ID, du.Capacity, du.Free, du.Used, du.Free_PC, du.Used_PC FROM [dbo].[Disk_Usage] du" +
          "\r\nLEFT JOIN Servers s on du.Server = s.UID" +
          "\r\nLEFT JOIN Disks d on du.Device_ID = d.UID" +
          "\r\nWHERE s.Server = '" + @server + "' AND" +
          "\r\ndu.Date > DATEADD(HOUR, -" + @period + ", GETDATE())" +
          "\r\nORDER BY du.Date";
   
    return _db.LoadData<DiskModel, dynamic>(sql, new { });
}
CREATE TABLE [dbo].[Disk_Usage](
	[UID] [int] IDENTITY(1,1) NOT NULL,
	[Date] [datetime2](7) NULL,
	[Server] [int] NULL,
	[Device_ID] [int] NULL,
	[Capacity] [bigint] NULL,
	[Free] [bigint] NULL,
	[Used] [bigint] NULL,
	[Free_PC] [decimal](6, 2) NULL,
	[Used_PC] [decimal](6, 2) NULL,
 CONSTRAINT [PK_Disk_Usage] PRIMARY KEY CLUSTERED 
(

I already did. CategoryProperty should be the name of the property. @D.Date is the value of the Date property.

Hi @n0bby

I see what you're doing now. Basically, you are querying a table to get the data for a single server. From this, you want a chart that has Date as the Category, Usage as the Value, and you want a series for each of the disks.

If this is correct, what I think you need to do is, instead of the foreach being on the whole data, you need to create a list of disk ids. Then use this list as the basis of your foreach loop and create a new "Data" variable that is the filter of your server data using the disk id.

i.e.

             var diskIds = Disk_Stats.Select(d => d.Disk_ID).Distinct();

             @foreach (var disk in diskIds) 
             {    
                    var diskData = Disk_Stats.Where(d=>d.Disk_ID==disk);

                    string dDate = @D.Date.ToString();
                    <RadzenLineSeries Smooth="false" Data="@diskData " 
                      CategoryProperty="@Date" Title="@Disk_ID" 
                      LineType="LineType.Dashed" ValueProperty="Used_PC">

                              <RadzenMarkers Visible="@showMarkers" 
                                MarkerType="MarkerType.Auto" />
                                          <RadzenSeriesDataLabels Visible="false" />
                   </RadzenLineSeries>
               }   

I've wrote this on the hoof with no testing, but it should at least give you an idea.

Hope this helps

Regards
Paul

1 Like

@Paul_Ruston Thank you very much!!!!! I had a play around with your suggestion and managed to get it working perfectly.

In the end, I had to wrap it in an IF statement to accept the VAR...

                        @if(Disk_Stats is not null)
                        {
                            var diskIds = Disk_Stats.Select(d => d.Disk_ID).Distinct();
                        
                            @foreach (var disk in diskIds) 
                            {    
                                var diskData = Disk_Stats.Where(d=>d.Disk_ID==disk);

                               <RadzenLineSeries Smooth="false" Data="@diskData" CategoryProperty="Date" Title="@disk" LineType="LineType.Dashed" ValueProperty="Used_PC">
                                    <RadzenMarkers Visible="@showMarkers" MarkerType="MarkerType.Auto" />
                                    <RadzenSeriesDataLabels Visible="false" />
                                </RadzenLineSeries>
                            }
                        }

1 Like