Thank you so much for your help, Durga.
Just documenting the full final code here for reference so future readers can benefit from it.
@using Syncfusion.Blazor.Charts
<SfChart Title="Oil Price Chart" Height="500px" Width="100%">
<ChartEvents OnAxisLabelRender="AxisLabelRender"></ChartEvents>
<ChartPrimaryXAxis ValueType="Syncfusion.Blazor.Charts.ValueType.DateTime"
IntervalType="Syncfusion.Blazor.Charts.IntervalType.Hours" Interval="4"
LabelFormat="HH">
<ChartAxisMajorGridLines Width="0"></ChartAxisMajorGridLines>
<ChartAxisMinorGridLines Width="0"></ChartAxisMinorGridLines>
<ChartStriplines>
@foreach (var g in OilPrices.GroupBy(x => x.TRADE_DATE.Date))
{
var first = g.First().TRADE_DATE;
if (first != OilPrices.First().TRADE_DATE.Date)
{
<ChartStripline Start="first"
SizeType="SizeType.Pixel"
Size="1"
DashArray="4,4"
Color="black"
Opacity="1"
ZIndex="ZIndex.Over"
Visible="true" />
}
}
</ChartStriplines>
<ChartMultiLevelLabels>
<!-- Day of week -->
<ChartMultiLevelLabel>
<ChartAxisMultiLevelLabelTextStyle Size="12px"></ChartAxisMultiLevelLabelTextStyle>
<ChartCategories>
@{
var grouped = OilPrices.GroupBy(x => x.TRADE_DATE.Date).ToList();
for (int i = 0; i < grouped.Count; i++)
{
var group = grouped[i];
var start = group.Min(x => x.TRADE_DATE);
var end = group.Max(x => x.TRADE_DATE).AddHours(1);
// For the last group, don't extend to avoid clipping
if (i == grouped.Count - 1)
end = end.AddHours(-1);
var dayName = start.ToString("ddd");
<ChartCategory Start="start" End="end" Text="@dayName"></ChartCategory>
}
}
</ChartCategories>
</ChartMultiLevelLabel>
<!-- Date -->
<ChartMultiLevelLabel>
<ChartAxisMultiLevelLabelTextStyle Size="12px"></ChartAxisMultiLevelLabelTextStyle>
<ChartCategories>
@{
var grouped = OilPrices.GroupBy(x => x.TRADE_DATE.Date).ToList();
for (int i = 0; i < grouped.Count; i++)
{
var group = grouped[i];
var start = group.Min(x => x.TRADE_DATE);
var end = group.Max(x => x.TRADE_DATE).AddHours(1);
if (i == grouped.Count - 1)
end = end.AddHours(-1);
var dateText = start.ToString("M/d/yyyy");
<ChartCategory Start="start" End="end" Text="@dateText"></ChartCategory>
}
}
</ChartCategories>
</ChartMultiLevelLabel>
</ChartMultiLevelLabels>
</ChartPrimaryXAxis>
<ChartPrimaryYAxis Title="Price" LabelFormat="N0" />
<ChartSeriesCollection>
<ChartSeries DataSource="@OilPrices" XName="TRADE_DATE" YName="MAXIMUM_PRICE" Name="Max" Type="Syncfusion.Blazor.Charts.ChartSeriesType.Area" Fill="#b3d8f7" Opacity="0.3" />
<ChartSeries DataSource="@OilPrices" XName="TRADE_DATE" YName="MINIMUM_PRICE" Name="Min" Type="Syncfusion.Blazor.Charts.ChartSeriesType.Area" Fill="#f7b3b3" Opacity="0.3" />
<ChartSeries DataSource="@OilPrices" XName="TRADE_DATE" YName="AVERAGE_PRICE" Name="Average" Type="Syncfusion.Blazor.Charts.ChartSeriesType.Line" Width="2" DashArray="5,2" Fill="#888" />
</ChartSeriesCollection>
<ChartLegendSettings Visible="true" />
<ChartTooltipSettings Enable="true" />
</SfChart>
@code {
// Only show HE labels for 1, 5, 9, 13, 17, 21
public void AxisLabelRender(Syncfusion.Blazor.Charts.AxisLabelRenderEventArgs args)
{
if (args.Axis.Name == "PrimaryXAxis")
{
long milliseconds = (long)args.Value;
DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeMilliseconds(milliseconds);
int hour = dateTimeOffset.UtcDateTime.Hour;
// If the calculated hour is 0 (midnight), display it as 1 instead.
if (hour == 0)
{
args.Text = "1";
}
else
{
// The other labels (5, 9, 13, 17, 21) are already correct.
args.Text = Convert.ToString(hour + 1);
}
}
}
public class HistoricalOilPrice
{
public DateTime TRADE_DATE { get; set; }
public int HOUR_ENDING { get; set; }
public double MAXIMUM_PRICE { get; init; }
public double MINIMUM_PRICE { get; init; }
public double AVERAGE_PRICE { get; init; }
public DateTime MAXIMUM_PRICE_DATE { get; set; }
public DateTime MINIMUM_PRICE_DATE { get; set; }
// public DateTime TRADE_DATETIME => TRADE_DATE.Date.AddHours(HOUR_ENDING - 1);
}
public List<HistoricalOilPrice> OilPrices = new List<HistoricalOilPrice>()
{
// 11/25/2025
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 25, 00, 0, 0), HOUR_ENDING = 1, MAXIMUM_PRICE = 13719.931, MINIMUM_PRICE = 7489, AVERAGE_PRICE = 10445 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 25, 01, 0, 0), HOUR_ENDING = 2, MAXIMUM_PRICE = 13712.913, MINIMUM_PRICE = 7180, AVERAGE_PRICE = 10289 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 25, 02, 0, 0), HOUR_ENDING = 3, MAXIMUM_PRICE = 13868.483, MINIMUM_PRICE = 7081, AVERAGE_PRICE = 10328 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 25, 03, 0, 0), HOUR_ENDING = 4, MAXIMUM_PRICE = 14141.359, MINIMUM_PRICE = 7057, AVERAGE_PRICE = 10487 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 25, 04, 0, 0), HOUR_ENDING = 5, MAXIMUM_PRICE = 14627.613, MINIMUM_PRICE = 7287.071, AVERAGE_PRICE = 10912 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 25, 05, 0, 0), HOUR_ENDING = 6, MAXIMUM_PRICE = 15450.165, MINIMUM_PRICE = 7954.41, AVERAGE_PRICE = 11760 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 25, 06, 0, 0), HOUR_ENDING = 7, MAXIMUM_PRICE = 16605.839, MINIMUM_PRICE = 9120.22, AVERAGE_PRICE = 12919 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 25, 07, 0, 0), HOUR_ENDING = 8, MAXIMUM_PRICE = 17028.84, MINIMUM_PRICE = 9957, AVERAGE_PRICE = 13349 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 25, 08, 0, 0), HOUR_ENDING = 9, MAXIMUM_PRICE = 16230.217, MINIMUM_PRICE = 9905, AVERAGE_PRICE = 12904 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 25, 09, 0, 0), HOUR_ENDING = 10, MAXIMUM_PRICE = 15310.13, MINIMUM_PRICE = 9881, AVERAGE_PRICE = 12294 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 25, 10, 0, 0), HOUR_ENDING = 11, MAXIMUM_PRICE = 14736.132, MINIMUM_PRICE = 9853, AVERAGE_PRICE = 11878 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 25, 11, 0, 0), HOUR_ENDING = 12, MAXIMUM_PRICE = 14433.803, MINIMUM_PRICE = 9764, AVERAGE_PRICE = 11595 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 25, 12, 0, 0), HOUR_ENDING = 13, MAXIMUM_PRICE = 14354.362, MINIMUM_PRICE = 9761, AVERAGE_PRICE = 11389 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 25, 13, 0, 0), HOUR_ENDING = 14, MAXIMUM_PRICE = 14313.819, MINIMUM_PRICE = 9724.755, AVERAGE_PRICE = 11255 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 25, 14, 0, 0), HOUR_ENDING = 15, MAXIMUM_PRICE = 14276.803, MINIMUM_PRICE = 9629.095, AVERAGE_PRICE = 11185 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 25, 15, 0, 0), HOUR_ENDING = 16, MAXIMUM_PRICE = 14782.532, MINIMUM_PRICE = 9636.309, AVERAGE_PRICE = 11352 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 25, 16, 0, 0), HOUR_ENDING = 17, MAXIMUM_PRICE = 15834.431, MINIMUM_PRICE = 9938, AVERAGE_PRICE = 11912 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 25, 17, 0, 0), HOUR_ENDING = 18, MAXIMUM_PRICE = 17075.608, MINIMUM_PRICE = 10637, AVERAGE_PRICE = 12750 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 25, 18, 0, 0), HOUR_ENDING = 19, MAXIMUM_PRICE = 17338.311, MINIMUM_PRICE = 10668, AVERAGE_PRICE = 12843 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 25, 19, 0, 0), HOUR_ENDING = 20, MAXIMUM_PRICE = 17408.959, MINIMUM_PRICE = 10447, AVERAGE_PRICE = 12763 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 25, 20, 0, 0), HOUR_ENDING = 21, MAXIMUM_PRICE = 17286.683, MINIMUM_PRICE = 10154, AVERAGE_PRICE = 12553 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 25, 21, 0, 0), HOUR_ENDING = 22, MAXIMUM_PRICE = 16925.582, MINIMUM_PRICE = 9553, AVERAGE_PRICE = 12121 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 25, 22, 0, 0), HOUR_ENDING = 23, MAXIMUM_PRICE = 16426.471, MINIMUM_PRICE = 8874, AVERAGE_PRICE = 11537 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 25, 23, 0, 0), HOUR_ENDING = 24, MAXIMUM_PRICE = 16010.116, MINIMUM_PRICE = 8160, AVERAGE_PRICE = 10984 },
// 11/26/2025
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 26, 00, 0, 0), HOUR_ENDING = 1, MAXIMUM_PRICE = 15769.147, MINIMUM_PRICE = 7641, AVERAGE_PRICE = 10630 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 26, 01, 0, 0), HOUR_ENDING = 2, MAXIMUM_PRICE = 15769.39, MINIMUM_PRICE = 7325, AVERAGE_PRICE = 10494 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 26, 02, 0, 0), HOUR_ENDING = 3, MAXIMUM_PRICE = 15929.102, MINIMUM_PRICE = 7173, AVERAGE_PRICE = 10505 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 26, 03, 0, 0), HOUR_ENDING = 4, MAXIMUM_PRICE = 16234.075, MINIMUM_PRICE = 7132, AVERAGE_PRICE = 10674 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 26, 04, 0, 0), HOUR_ENDING = 5, MAXIMUM_PRICE = 16800.84, MINIMUM_PRICE = 7286, AVERAGE_PRICE = 11068 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 26, 05, 0, 0), HOUR_ENDING = 6, MAXIMUM_PRICE = 17767.443, MINIMUM_PRICE = 7864, AVERAGE_PRICE = 11874 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 26, 06, 0, 0), HOUR_ENDING = 7, MAXIMUM_PRICE = 18970.799, MINIMUM_PRICE = 8928, AVERAGE_PRICE = 12903 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 26, 07, 0, 0), HOUR_ENDING = 8, MAXIMUM_PRICE = 19317.352, MINIMUM_PRICE = 9511, AVERAGE_PRICE = 13347 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 26, 08, 0, 0), HOUR_ENDING = 9, MAXIMUM_PRICE = 18431.998, MINIMUM_PRICE = 9667, AVERAGE_PRICE = 13038 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 26, 09, 0, 0), HOUR_ENDING = 10, MAXIMUM_PRICE = 17100.629, MINIMUM_PRICE = 9908, AVERAGE_PRICE = 12548 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 26, 10, 0, 0), HOUR_ENDING = 11, MAXIMUM_PRICE = 16069.225, MINIMUM_PRICE = 9998, AVERAGE_PRICE = 12145 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 26, 11, 0, 0), HOUR_ENDING = 12, MAXIMUM_PRICE = 15372.109, MINIMUM_PRICE = 9983, AVERAGE_PRICE = 11845 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 26, 12, 0, 0), HOUR_ENDING = 13, MAXIMUM_PRICE = 14870.324, MINIMUM_PRICE = 9866.058, AVERAGE_PRICE = 11582 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 26, 13, 0, 0), HOUR_ENDING = 14, MAXIMUM_PRICE = 14496.068, MINIMUM_PRICE = 9753, AVERAGE_PRICE = 11403 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 26, 14, 0, 0), HOUR_ENDING = 15, MAXIMUM_PRICE = 14334.454, MINIMUM_PRICE = 9711.327, AVERAGE_PRICE = 11340 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 26, 15, 0, 0), HOUR_ENDING = 16, MAXIMUM_PRICE = 14741.784, MINIMUM_PRICE = 9772.789, AVERAGE_PRICE = 11485 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 26, 16, 0, 0), HOUR_ENDING = 17, MAXIMUM_PRICE = 15747.976, MINIMUM_PRICE = 10188.038, AVERAGE_PRICE = 12005 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 26, 17, 0, 0), HOUR_ENDING = 18, MAXIMUM_PRICE = 16763.222, MINIMUM_PRICE = 10928, AVERAGE_PRICE = 12834 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 26, 18, 0, 0), HOUR_ENDING = 19, MAXIMUM_PRICE = 17065.315, MINIMUM_PRICE = 10846, AVERAGE_PRICE = 12880 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 26, 19, 0, 0), HOUR_ENDING = 20, MAXIMUM_PRICE = 17009.487, MINIMUM_PRICE = 10668, AVERAGE_PRICE = 12758 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 26, 20, 0, 0), HOUR_ENDING = 21, MAXIMUM_PRICE = 16843.302, MINIMUM_PRICE = 10515, AVERAGE_PRICE = 12575 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 26, 21, 0, 0), HOUR_ENDING = 22, MAXIMUM_PRICE = 16385.782, MINIMUM_PRICE = 10154, AVERAGE_PRICE = 12206 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 26, 22, 0, 0), HOUR_ENDING = 23, MAXIMUM_PRICE = 15774.06, MINIMUM_PRICE = 9634, AVERAGE_PRICE = 11659 },
new HistoricalOilPrice { TRADE_DATE = new DateTime(2025, 11, 26, 23, 0, 0), HOUR_ENDING = 24, MAXIMUM_PRICE = 15204.069, MINIMUM_PRICE = 9038, AVERAGE_PRICE = 11122 }
};
}