ブログ

割とコンピュータよりの情報をお届けします。

Plotly.Blazorのサンプル

.NET 8のリリースから半年近く経って、Plotly.Blazorのサンプルが増えていた。

Plotly.Blazorのサンプルが増えていたのでプロットしてみていた。とりあえず.NET6でプロットしたい場合にはサンプルのままで問題ない。
だが、縦横比を1:1にするときはどのようにするかが難しかった。とりあえずnugetパッケージをPlotly.Blazor(4.3.0)をインストール。
.NET 8になって、明示的にApp.razorのRoutesに@rendermodeを指定する必要が出ているようだ。以下Blazor serverで実装していく。
それからplotly.jsを追加していく。

<Routes @rendermode=RenderMode.InteractiveServer />
<script src="_content/Plotly.Blazor/plotly-latest.min.js" type="text/javascript"></script>
<script src="_content/Plotly.Blazor/plotly-interop.js" type="text/javascript"></script>
<script src="_framework/blazor.web.js"></script>

_Imports.razorに以下を追加する。

@using Plotly.Blazor
@using Plotly.Blazor.Traces

例えば、Home.razorに追加してみる。

@page "/"
@inject IJSRuntime JS
<PageTitle>Home</PageTitle>

<PlotlyChart
    @bind-Config="config"
    @bind-Layout="layout"
    @bind-Data="data" 
    @ref="chart"
    style="height: 500px;"/>

@code
{
    PlotlyChart? chart;
    Config config = new Config();
    Layout layout = new Layout();

    // Using of the interface IList is important for the event callback!
    IList<ITrace> data = new List<ITrace>
    {
        new Scatter
        {
            Name = "Sample circle small",
            Mode = Plotly.Blazor.Traces.ScatterLib.ModeFlag.Lines
                | Plotly.Blazor.Traces.ScatterLib.ModeFlag.Markers,
            X = new List<object>(),
            Y = new List<object>()
        },
        new Scatter
        {
            Name = "Sample circle large",
            Mode = Plotly.Blazor.Traces.ScatterLib.ModeFlag.Lines,
            X = new List<object>(),
            Y = new List<object>(),
            Line = new Plotly.Blazor.Traces.ScatterLib.Line() {
                Width = 1.85M,
                Dash = "3 12 5",
            },
        },
        new Scatter
        {
            Name = "Sample circle",
            Mode = Plotly.Blazor.Traces.ScatterLib.ModeFlag.Lines,
            X = new List<object>(),
            Y = new List<object>(),
            Line = new Plotly.Blazor.Traces.ScatterLib.Line() {
                Width = 0.5M,
                Dash = "dashdot",
            },
        },
    };

    private void AddData(int count = 360, double radius = 100D, Scatter? scatter = null)
    {
        Scatter refToScatter = (Scatter)data[0];
        if (scatter != null)
            refToScatter = scatter;

        double interval = 360D / (count - 1);
        for (int i = 0; i < count; i++)
        {
            double theta = ((double)i) * interval / 180D * Math.PI;
            double r = radius;
            refToScatter.X.Add(r * Math.Cos(theta));
            refToScatter.Y.Add(r * Math.Sin(theta));
        }
    }

    protected override void OnInitialized()
    {
        IList<Plotly.Blazor.LayoutLib.YAxis> ys = new List<Plotly.Blazor.LayoutLib.YAxis>();
        ys.Add(new Plotly.Blazor.LayoutLib.YAxis()
            {
                ScaleAnchor = "x",
            });
        layout.YAxis = ys;
        layout.AutoSize = true;

        AddData(count: 31, radius: 100D, scatter: (Scatter)data[0]);
        AddData(count: 98, radius: 60D, scatter: (Scatter)data[1]);
        AddData(count: 67, radius: 80D, scatter: (Scatter)data[2]);

        
    }
}


注意する点として、線幅がDoubleではなくDecimalで定義されている。とりあえず、PlotlyChartのstyleにheightを指定しているが、リサイズしても追従してこない。うまい方法がないかを探しているが、例えば、App.razorの
<script src="_framework/blazor.web.js"></script>
の後くらいに以下のようなコードを挿入して

    <script>
        window.viewportChangeCallback = (dotnetObject) => {
            window.addEventListener('load', () => {
                dotnetObject.invokeMethodAsync('OnResize', window.innerWidth, window.innerHeight);
            });
            window.addEventListener('resize', () => {
                dotnetObject.invokeMethodAsync('OnResize', window.innerWidth, window.innerHeight);
            });
        }
    </script>

Home.razorのコード部分に以下を追加してやる。引数はとりあえず使用していないが、何かあった時のために渡している。


    [JSInvokable]
    public void OnResize(int width, int height)
    {
        chart?.Update();
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            await JS.InvokeVoidAsync("window.viewportChangeCallback", DotNetObjectReference.Create(this));
        }
    }

ここまで書いておいてなんだが、このOnResizeの対応は別に書かなくてもConfigのプロパティにResponsiveというのがあるので、これで多くの場合には事足りるようだ。

    Config config = new Config()
    {
        Responsive = true
    };

3次元プロットも以下のようになる。

@page "/Chart3D"

<PlotlyChart @bind-Config="config"
             @bind-Layout="layout"
             @bind-Data="data"
             @ref="chart"
             @bind-Style="Style" />

@code {
    PlotlyChart? chart;
    Config config = new Config()
    { 
        Responsive = true
    };
    Layout layout = new Layout();

    [Parameter]
    public string? Style { get; set; } = "height: 900px;";

    IList<ITrace> data = new List<ITrace>
    {
        new Scatter3D
        {
            Name = "Sample helix 3d",
            Mode = Plotly.Blazor.Traces.Scatter3DLib.ModeFlag.Lines
                | Plotly.Blazor.Traces.Scatter3DLib.ModeFlag.Markers,
            X = new List<object>(),
            Y = new List<object>(),
            Z = new List<object>(),
            Marker = new Plotly.Blazor.Traces.Scatter3DLib.Marker()
            {
                Size = 1M,
            }
        },
    };

    private void AddData(
        int count = 360,
        double radius = 100D,
        double lead = 10D,
        Scatter3D? scatter = null)
    {
        Scatter3D refToScatter = (Scatter3D)data[0];
        if (scatter != null)
            refToScatter = scatter;

        double interval = 360D / (count - 1);
        for (int i = 0; i < count; i++)
        {
            double theta = ((double)i) * interval / 180D * Math.PI;
            double r = radius;
            refToScatter.X.Add(r * Math.Cos(theta));
            refToScatter.Y.Add(r * Math.Sin(theta));
            refToScatter.Z.Add(interval / 360 * lead * i);
        }
    }

    protected override void OnInitialized()
    {
        IList<Plotly.Blazor.LayoutLib.Scene> scene = new List<Plotly.Blazor.LayoutLib.Scene>();
        scene.Add(new Plotly.Blazor.LayoutLib.Scene() {
                AspectMode = Plotly.Blazor.LayoutLib.SceneLib.AspectModeEnum.Data,
                AspectRatio = new Plotly.Blazor.LayoutLib.SceneLib.AspectRatio()
                    {
                        X = 1M,
                        Y = 1M,
                        Z = 1M
                    },
            }
        );
        layout.Scene = scene;


        AddData(count: 31, radius: 100D, lead: 400D, scatter: (Scatter3D)data[0]);
    }
    
}
2024/05/02 コンピュータ   TakeMe
< 前の記事     一覧へ    

コメント送信フォーム


※ Eメールは公開されません
Loading...
 画像の文字を入力してください