Skip to content

Commit

Permalink
Merge pull request #425 from DaltonBritton/main
Browse files Browse the repository at this point in the history
Added Prepend/Extend Trace Methods for Scatter3D plots
  • Loading branch information
sean-mcl authored Jun 17, 2024
2 parents c2a687f + a2df7d1 commit 2b836d1
Show file tree
Hide file tree
Showing 8 changed files with 685 additions and 0 deletions.
218 changes: 218 additions & 0 deletions Plotly.Blazor.Examples/Components/Scatter3DChart.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
@using Plotly.Blazor.LayoutLib
@using Plotly.Blazor.Traces.Scatter3DLib

<PlotlyChart style="height: 60vh; min-height: 350px" @bind-Config="config" @bind-Layout="layout" @bind-Data="data" @ref="chart" AfterRender="ExtendData"/>
<br/>
<div class="d-flex gap-1 justify-end">
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="() => chart.Clear()">Clear</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="DeleteScatter">Pop</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="AddScatter">Push</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="Restyle">Rename</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="PrependData">Prepend</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="ExtendData">Extend</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="PrependWithLimit">Prepend (Max. 100)</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="ExtendWithLimit">Extend (Max. 100)</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="ExportImage">Show Image</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="DownloadImage">Download</MudButton>
</div>
<p>NumPoints: @numPoints</p>

@if (imgSource != null)
{
<div style="margin-top:auto; margin-bottom:auto;text-align:center;">
<br/>
<h2>Export as an image</h2>
<img alt="image" src="@imgSource"/>
</div>
}

@code
{
[CascadingParameter] private MudTheme Theme { get; set; }

private PlotlyChart chart;
private Config config;
private Layout layout;
private IList<ITrace> data;
private string imgSource;

private int numPoints = 0;

/// <inheritdoc />
protected override void OnInitialized()
{
config = new Config
{
Responsive = true
};

layout = new Layout
{
Title = new Title
{
Text = GetType().Name
},
PaperBgColor = Theme.PaletteDark.Surface.ToString(),
PlotBgColor = Theme.PaletteDark.Surface.ToString(),
Font = new Font
{
Color = Theme.PaletteDark.TextPrimary.ToString()
},
YAxis = new List<YAxis>
{
new()
{
Title = new LayoutLib.YAxisLib.Title {Text = "Scatter Unit"}
}
}
};

data = new List<ITrace>
{
new Scatter3D
{
Name = "ScatterTrace",
Mode = ModeFlag.Lines | ModeFlag.Markers,
X = new List<object>(),
Y = new List<object>(),
Z = new List<object>()
}
};

base.OnInitialized();
}

private async Task AddScatter()
{
var (x, y, z) = Helper.GenerateData3D(0, 100);
await chart.AddTrace(new Scatter3D
{
Name = $"ScatterTrace{data.Count + 1}",
Mode = ModeFlag.Lines | ModeFlag.Markers,
X = x,
Y = y,
Z = z,
});
}

private async Task DeleteScatter()
{
await chart.DeleteTrace(0);
}

private async Task ExportImage()
{
imgSource = await chart.ToImage(ImageFormat.Png, 400, 800);
}

private async Task DownloadImage()
{
await chart.DownloadImage(ImageFormat.Png, 400, 800, "ScatterExample");
}

private async void ExtendData()
{
const int count = 100;

if (chart.Data.FirstOrDefault() is not Scatter3D scatter3D)
{
return;
}

int? max = (int?) scatter3D.Z?.Max();
var (x, y, z) = Helper.GenerateData3D(max + 1 ?? 0, max + 1 + count ?? count);
if (scatter3D.X != null && (!scatter3D.X.Any() || !scatter3D.Y.Any() || !scatter3D.Z.Any()))
{
scatter3D.X.AddRange(x);
scatter3D.Y.AddRange(y);
scatter3D.Z.AddRange(z);
await chart.React();
}
else
{
await chart.ExtendTrace3D(x, y, z, data.IndexOf(scatter3D));
}

numPoints += x.Count;
}

private async Task ExtendWithLimit()
{
const int count = 100;
const int limit = 100;

if (chart.Data.FirstOrDefault() is not Scatter3D scatter)
{
return;
}

var max = (int?) scatter.Z?.Max();
var (x, y, z) = Helper.GenerateData3D(max + 1 ?? 0, max + 1 + count ?? count);
if (!scatter.X.Any() || !scatter.Y.Any() || !scatter.Z.Any())
{
scatter.X.AddRange(x);
scatter.Y.AddRange(y);
scatter.Z.AddRange(z);
await chart.React();
}
else
{
await chart.ExtendTrace3D(x, y, z, data.IndexOf(scatter), limit);
}
}

private async Task PrependData()
{
const int count = 100;

if (chart.Data.FirstOrDefault() is not Scatter3D scatter)
{
return;
}

var min = (int?) scatter.Z?.Min();
var (x, y,z) = Helper.GenerateData3D(min - 1 ?? 0, min - 1 - count ?? count * -1);
if (!scatter.X.Any() || !scatter.Y.Any() || !scatter.Z.Any())
{
scatter.X.AddRange(x);
scatter.Y.AddRange(y);
scatter.Z.AddRange(z);
await chart.React();
}
else
{
await chart.PrependTrace3D(x, y, z, data.IndexOf(scatter));
}
}

private async void PrependWithLimit()
{
const int count = 100;
const int limit = 100;

if (chart.Data.FirstOrDefault() is not Scatter3D scatter)
{
return;
}

var min = (int?) scatter.Z?.Min();
var (x, y,z) = Helper.GenerateData3D(min - 1 ?? 0, min - 1 - count ?? count * -1);
if (!scatter.X.Any() || !scatter.Y.Any() || !scatter.Z.Any())
{
scatter.X.AddRange(x);
scatter.Y.AddRange(y);
scatter.Z.AddRange(z);
await chart.React();
}
else
{
await chart.PrependTrace3D(x, y, z, data.IndexOf(scatter), limit);
}
}

private async Task Restyle()
{
var updateScatterChart = new Scatter {Name = "Restyled Name"};
await chart.Restyle(updateScatterChart, 0);
}
}
32 changes: 32 additions & 0 deletions Plotly.Blazor.Examples/Helper.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Diagnostics.CodeAnalysis;
using Plotly.Blazor.Traces;
using Plotly.Blazor.Traces.Scatter3DLib.ProjectionLib;

namespace Plotly.Blazor.Examples
{
Expand Down Expand Up @@ -81,6 +82,37 @@ public static (List<object> X, List<object> Y) GenerateData(int startIndex, int

return (x, y);
}


/// <summary>
/// Generates the data.
/// </summary>
/// <param name="startIndex">The start index.</param>
/// <param name="stopIndex">Index of the stop.</param>
/// <param name="method">The method.</param>
/// <returns>
/// System.ValueTuple&lt;List&lt;System.Nullable&lt;System.Double&gt;&gt;, List&lt;System.Nullable&lt;
/// System.Double&gt;&gt;, List&lt;System.Nullable&lt;System.Double&gt;&gt;&gt;.
/// </returns>
public static (List<object> X, List<object> Y, List<object> Z) GenerateData3D(int startIndex, int stopIndex,
GenerateMethod method = GenerateMethod.Sin)
{
var x = new List<object>();
var y = new List<object>();
var z = new List<object>();

var start = Math.Min(startIndex, stopIndex);
var stop = Math.Max(startIndex, stopIndex);

for (var i = start; i < stop; i++)
{
x.Add(MathF.Sin(i));
y.Add(MathF.Cos(i));
z.Add(i);
}

return (x, y, z);
}

private static double Randomize(this int number, GenerateMethod method = GenerateMethod.Sin)
{
Expand Down
6 changes: 6 additions & 0 deletions Plotly.Blazor.Examples/Pages/Scatter3DPage.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@page "/Scatter3DPage"


<Example Title="Scatter Chart 3D" Url="Plotly.Blazor.Examples/Components/RibbonChart.razor">
<Scatter3DChart/>
</Example>
1 change: 1 addition & 0 deletions Plotly.Blazor.Examples/Shared/NavMenu.razor
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<MudDrawer @bind-Open="@open" ClipMode="DrawerClipMode.Never" Breakpoint="Breakpoint.Xl" Elevation="0" Variant="@DrawerVariant.Responsive">
<MudNavMenu>
<MudNavLink Match="NavLinkMatch.All" Href="@($"{NavManager.BaseUri}")">Scatter</MudNavLink>
<MudNavLink Match="NavLinkMatch.All" Href="@($"{NavManager.BaseUri}Scatter3DPage")">Scatter3D</MudNavLink>
<MudNavLink Match="NavLinkMatch.All" Href="@($"{NavManager.BaseUri}live-data")">Live Data</MudNavLink>
<MudNavLink Match="NavLinkMatch.All" Href="@($"{NavManager.BaseUri}bar")">Bar</MudNavLink>
<MudNavLink Match="NavLinkMatch.All" Href="@($"{NavManager.BaseUri}pie")">Pie</MudNavLink>
Expand Down
Loading

0 comments on commit 2b836d1

Please sign in to comment.