From d91fe84a6e4c1b04fc7909d026777ae1fc002733 Mon Sep 17 00:00:00 2001 From: Kevin Schneider Date: Thu, 16 Apr 2026 19:31:24 +0200 Subject: [PATCH 1/7] Add Sankey node align and encoded node/link array support (plotly.js 2.28.0) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit I — Sankey node align: - Add `SankeyNodeAlign` StyleParam DU (Left/Right/Center/Justify) - Add `?Align: StyleParam.SankeyNodeAlign` to `SankeyNodes.init`/`SankeyNodes.style` - Add `?NodeAlign` to `Chart.Sankey` F# convenience overload - Tests: 2 new assertions verifying `"align"` serializes correctly on the node object Commit K — Sankey encoded node and link arrays: - Add `?ColorEncoded`, `?CustomDataEncoded`, `?XEncoded`, `?YEncoded` to `SankeyNodes.init`/`SankeyNodes.style` - Add `?SourceEncoded`, `?TargetEncoded`, `?ValueEncoded`, `?ColorEncoded`, `?CustomDataEncoded` to `SankeyLinks.init`/`SankeyLinks.style` - Encoded params share the same plotly.js property key as their plain counterparts; encoded version wins when both are provided - Tests: 9 new assertions verifying all node and link encoded fields serialize as `{"bdata":...}` objects - Update PlotlyJS_2_28_Parity.md to reflect both commits as done (942 tests passing) Co-Authored-By: Claude Sonnet 4.6 --- plans/PlotlyJS_2_28_Parity.md | 167 ++++++++++++++++++ .../ChartDomain/ChartDomain_Relations.fs | 3 + .../CommonAbstractions/StyleParams.fs | 18 ++ .../Traces/ObjectAbstractions/Sankey.fs | 54 +++++- .../TestCharts/UpstreamFeatures/2.28.fs | 59 +++++++ .../CoreTests/UpstreamFeatures/2.28.fs | 62 +++++++ 6 files changed, 355 insertions(+), 8 deletions(-) create mode 100644 plans/PlotlyJS_2_28_Parity.md diff --git a/plans/PlotlyJS_2_28_Parity.md b/plans/PlotlyJS_2_28_Parity.md new file mode 100644 index 00000000..3ac34978 --- /dev/null +++ b/plans/PlotlyJS_2_28_Parity.md @@ -0,0 +1,167 @@ +# plotly.js 2.28.0 Full Parity Plan + +## Summary + +Plotly.NET has been targeting plotly.js 2.28.0 since the bundle was bumped in commit `62a96500`. The bulk of the work — encoded typed array support across all trace types and the F# Chart API — was completed in a long series of commits tracked in [EncodedArraySupport.md](EncodedArraySupport.md). This document identifies the **remaining gaps** needed for full 2.28.0 parity and lays out a plan to close them. + +## plotly.js 2.28.0 Release Features + +Source: https://github.com/plotly/plotly.js/releases/tag/v2.28.0 + +### Added + +1. **Sankey node `align`** — horizontal alignment option for sankey nodes ([#6800](https://github.com/plotly/plotly.js/pull/6800)) +2. **Virtual-WebGL** — option to load a `virtual-webgl` script for multiple WebGL 1 contexts ([#6784](https://github.com/plotly/plotly.js/pull/6784)) +3. **Encoded typed arrays** — base64 `bdata`/`dtype`/`shape` object form for data arrays ([#5230](https://github.com/plotly/plotly.js/pull/5230)) + +### Fixed (JS-only, no Plotly.NET surface needed) + +- scattergl rendering on M1 mac +- sankey hover highlighting across multiple traces +- rangeslider drag at x=0 +- duplicated major/minor ticks in calc data +- range defaults respecting `minallowed`/`maxallowed` +- `scattergl` legend with `marker.angle` array +- `scatterpolargl` `line.shape` schema cleanup + +The fixes are JS-runtime-only and do not require Plotly.NET changes — they are resolved by shipping the updated `plotly-2.28.0.min.js` bundle, which is already in place. + +## Current Implementation Status + +| Feature | F# Trace Layer | F# Chart API | C# Wrapper | Tests | Status | +|---------|:-:|:-:|:-:|:-:|---| +| Encoded typed arrays | ✅ | ✅ | ❌ | ✅ 942 passing | H3 pending | +| Sankey node `align` | ✅ | ✅ | ❌ | ✅ | Done (Commit I) | +| Virtual-WebGL | ❌ | N/A | N/A | ❌ | Not started | +| Sankey encoded arrays (nodes + links) | ✅ | ✅ | ❌ | ✅ | Done (Commit K) | +| ParallelCoord/Categories `keyValuesEncoded` | ✅ Dimension-level | ❌ deferred | ❌ | ❌ | Deferred in H1-G | +| Bundled plotly.js 2.28.0 | ✅ | — | — | — | Done | + +## Remaining Work Packages + +### Commit I: Sankey node `align` property + +**Priority: High** — this is a user-visible new feature from 2.28.0 that has no Plotly.NET surface at all. + +Scope: + +- add a `SankeyNodeAlign` `StyleParam` enum with values matching plotly.js: `Left`, `Right`, `Center`, `Justify` (plotly.js values: `"left"`, `"right"`, `"center"`, `"justify"`) +- add `?Align: StyleParam.SankeyNodeAlign` to `SankeyNodes.init` and `SankeyNodes.style` +- add `?NodeAlign` to `Chart.Sankey` (F#) and `Chart.Sankey` (C#) forwarding to `SankeyNodes` +- verify the `align` property appears in the plotly.js schema for sankey nodes before settling on the exact enum values + +Files to change: + +- `src/Plotly.NET/CommonAbstractions/StyleParam.fs` — add `SankeyNodeAlign` DU +- `src/Plotly.NET/Traces/ObjectAbstractions/Sankey.fs` — add `?Align` param to `SankeyNodes` +- `src/Plotly.NET/ChartAPI/ChartDomain/ChartDomain_Relations.fs` — add `?NodeAlign` to `Chart.Sankey` +- `src/Plotly.NET.CSharp/ChartAPI/ChartDomain.cs` — add `NodeAlign` param to C# `Chart.Sankey` + +Tests: + +- add a test fixture in `tests/Common/FSharpTestBase/TestCharts/UpstreamFeatures/2.28.fs` +- add assertions in `tests/CoreTests/CoreTests/UpstreamFeatures/2.28.fs` +- verify serialization produces `"node": { "align": "right" }` (or whichever value) + +### Commit J: Virtual-WebGL config option + +**Priority: Low** — niche feature for pages with many WebGL contexts. Plotly.NET charts are typically rendered one-at-a-time in HTML, but notebook and multi-chart scenarios could benefit. + +Scope: + +- determine how plotly.js exposes this option (likely a config-level flag or a separate script include) +- if it is a config option: add it to `Config.fs` as `?VirtualWebGL: bool` +- if it is a script include: add support in `DisplayOptions` to inject the virtual-webgl script tag before the plotly.js bundle +- add minimal test coverage + +Files to change (depending on mechanism): + +- `src/Plotly.NET/Config/Config.fs` — if config-level +- `src/Plotly.NET/DisplayOptions/DisplayOptions.fs` — if script-level +- corresponding C# surface if applicable + +Note: This requires further investigation of the plotly.js implementation ([#6784](https://github.com/plotly/plotly.js/pull/6784)) to determine the exact integration point. May be purely client-side and not need a Plotly.NET wrapper at all. + +### Commit K: Sankey encoded arrays at Chart API level + +**Priority: Medium** — trace-level encoded support already exists; this is about exposing it ergonomically at the Chart API. + +Scope: + +- design encoded array support for `SankeyNodes` and `SankeyLinks`: + - add `?LabelEncoded`, `?ColorEncoded`, `?XEncoded`, `?YEncoded`, `?CustomDataEncoded` to `SankeyNodes.init`/`SankeyNodes.style` + - add `?SourceEncoded`, `?TargetEncoded`, `?ValueEncoded`, `?LabelEncoded`, `?ColorEncoded`, `?CustomDataEncoded` to `SankeyLinks.init`/`SankeyLinks.style` +- add an encoded `Chart.Sankey` overload that accepts nodes/links built with encoded arrays +- add tests + +Files to change: + +- `src/Plotly.NET/Traces/ObjectAbstractions/Sankey.fs` +- `src/Plotly.NET/ChartAPI/ChartDomain/ChartDomain_Relations.fs` +- test fixtures and assertions in upstream 2.28 test files + +### Commit L: ParallelCoord / ParallelCategories `keyValuesEncoded` convenience + +**Priority: Low** — `Dimension.initParallel` already supports `ValuesEncoded`, so users can build encoded dimensions manually. This is a convenience-only gap. + +Scope: + +- add `Chart.ParallelCoord(keyValuesEncoded = ...)` and `Chart.ParallelCategories(keyValuesEncoded = ...)` overloads +- delegate to existing `Dimension.initParallel(ValuesEncoded = ...)` internally +- add tests + +### Commit M: C# surface projection (Phase H3) + +**Priority: High** — blocks any C# consumer from using encoded arrays through the idiomatic API. + +Scope: + +- mirror the finalized F# encoded overloads into `Plotly.NET.CSharp` +- focus on foundational chart roots first: + - `Chart.Scatter`, `Chart.Bar`, `Chart.Histogram`, `Chart.Heatmap`, `Chart.Scatter3D`, etc. +- avoid duplicating every convenience overload — only add C# encoded overloads for the most commonly used chart types +- add C# interop tests in `tests/CoreTests/CSharpInteroperabilityTests/` + +Files to change: + +- `src/Plotly.NET.CSharp/ChartAPI/Chart2D.cs` +- `src/Plotly.NET.CSharp/ChartAPI/Chart3D.cs` +- `src/Plotly.NET.CSharp/ChartAPI/ChartDomain.cs` +- `src/Plotly.NET.CSharp/ChartAPI/ChartMap.cs` +- `src/Plotly.NET.CSharp/ChartAPI/ChartPolar.cs` +- `src/Plotly.NET.CSharp/ChartAPI/ChartSmith.cs` +- `src/Plotly.NET.CSharp/ChartAPI/ChartTernary.cs` +- `src/Plotly.NET.CSharp/ChartAPI/ChartCarpet.cs` +- test files in `tests/CoreTests/CSharpInteroperabilityTests/` + +### Commit N: Documentation updates + +**Priority: Medium** — users need to know encoded arrays exist. + +Scope: + +- add a new doc page (e.g. `docs/general/encoded-arrays.fsx`) showing how to use `EncodedTypedArray` with common chart types +- update the Sankey docs page to show the `align` property +- mention 2.28.0 features in RELEASE_NOTES.md for the upcoming version + +## Recommended Commit Order + +| Order | Commit | Description | Dependency | +|:---:|:---:|---|---| +| 1 | **I** | Sankey `align` property | None | +| 2 | **K** | Sankey encoded Chart API | None (can parallel with I) | +| 3 | **M** | C# encoded surface (H3) | H2 complete ✅ | +| 4 | **L** | ParallelCoord/Categories encoded convenience | H1-D-Splom complete ✅ | +| 5 | **J** | Virtual-WebGL (investigation + possible impl) | None | +| 6 | **N** | Documentation | After I, K, M | + +Commits I and K are independent and can be developed in parallel. Commit M (C# surface) is the largest remaining effort. Commit J requires upstream investigation and may turn out to be unnecessary for the Plotly.NET surface. + +## Verification + +After all commits: + +- `.\build.cmd runTestsAll` should pass +- all upstream 2.28 test fixtures should be green +- C# interop tests should cover at least the foundational encoded chart roots +- manual console samples should render correctly in a browser diff --git a/src/Plotly.NET/ChartAPI/ChartDomain/ChartDomain_Relations.fs b/src/Plotly.NET/ChartAPI/ChartDomain/ChartDomain_Relations.fs index 798eec8f..4e2e4bdf 100644 --- a/src/Plotly.NET/ChartAPI/ChartDomain/ChartDomain_Relations.fs +++ b/src/Plotly.NET/ChartAPI/ChartDomain/ChartDomain_Relations.fs @@ -364,6 +364,7 @@ module ChartDomain_Relations = /// Sets the orientation of the Sankey diagram. /// Sets the text font of this trace. /// If value is `snap` (the default), the node arrangement is assisted by automatic snapping of elements to preserve space between nodes specified via `nodepad`. If value is `perpendicular`, the nodes can only move along a line perpendicular to the flow. If value is `freeform`, the nodes can freely move on the plane. If value is `fixed`, the nodes are stationary. + /// Sets the horizontal alignment of the nodes in the Sankey diagram. If value is `justify` (the default), the nodes are spread to fill the width. If value is `left`, `right`, or `center`, the nodes are aligned accordingly. /// Sets the value formatting rule using d3 formatting mini-languages which are very similar to those in Python. For numbers, see: https://github.com/d3/d3-format/tree/v1.4.5#d3-format. /// Adds a unit to follow the value in the hover tooltip. Add a space if a separation is necessary from the value. /// If set to false, ignore the global default settings set in `Defaults` @@ -388,6 +389,7 @@ module ChartDomain_Relations = ?Orientation: StyleParam.Orientation, ?TextFont: Font, ?Arrangement: StyleParam.CategoryArrangement, + ?NodeAlign: StyleParam.SankeyNodeAlign, ?ValueFormat: string, ?ValueSuffix: string, ?UseDefaults: bool @@ -400,6 +402,7 @@ module ChartDomain_Relations = SankeyNodes.init ( Label = nodeLabels, Line = nodeOutline, + ?Align = NodeAlign, ?Color = NodeColor, ?Thickness = NodeThickness, ?Groups = NodeGroups diff --git a/src/Plotly.NET/CommonAbstractions/StyleParams.fs b/src/Plotly.NET/CommonAbstractions/StyleParams.fs index 77438ba3..74c91ed8 100644 --- a/src/Plotly.NET/CommonAbstractions/StyleParams.fs +++ b/src/Plotly.NET/CommonAbstractions/StyleParams.fs @@ -2684,6 +2684,24 @@ module StyleParam = // #S# //-------------------------- + [] + type SankeyNodeAlign = + | Left + | Right + | Center + | Justify + + static member toString = + function + | Left -> "left" + | Right -> "right" + | Center -> "center" + | Justify -> "justify" + + static member convert = SankeyNodeAlign.toString >> box + override this.ToString() = this |> SankeyNodeAlign.toString + member this.Convert() = this |> SankeyNodeAlign.convert + [] type ScaleAnchor = | False diff --git a/src/Plotly.NET/Traces/ObjectAbstractions/Sankey.fs b/src/Plotly.NET/Traces/ObjectAbstractions/Sankey.fs index 9ae58ac3..4ee9d7ce 100644 --- a/src/Plotly.NET/Traces/ObjectAbstractions/Sankey.fs +++ b/src/Plotly.NET/Traces/ObjectAbstractions/Sankey.fs @@ -11,8 +11,11 @@ type SankeyNodes() = static member init ( + ?Align: StyleParam.SankeyNodeAlign, ?Color: Color, + ?ColorEncoded: EncodedTypedArray, ?CustomData: seq<#IConvertible>, + ?CustomDataEncoded: EncodedTypedArray, ?Groups: seq<#seq>, ?HoverInfo: StyleParam.HoverInfo, ?HoverLabel: Hoverlabel, @@ -23,13 +26,18 @@ type SankeyNodes() = ?Pad: int, ?Thickness: int, ?X: seq<#IConvertible>, - ?Y: seq<#IConvertible> + ?XEncoded: EncodedTypedArray, + ?Y: seq<#IConvertible>, + ?YEncoded: EncodedTypedArray ) = SankeyNodes() |> SankeyNodes.style ( + ?Align = Align, ?Color = Color, + ?ColorEncoded = ColorEncoded, ?CustomData = CustomData, + ?CustomDataEncoded = CustomDataEncoded, ?Groups = Groups, ?HoverInfo = HoverInfo, ?HoverLabel = HoverLabel, @@ -40,14 +48,18 @@ type SankeyNodes() = ?Pad = Pad, ?Thickness = Thickness, ?X = X, - ?Y = Y - + ?XEncoded = XEncoded, + ?Y = Y, + ?YEncoded = YEncoded ) static member style ( + ?Align: StyleParam.SankeyNodeAlign, ?Color: Color, + ?ColorEncoded: EncodedTypedArray, ?CustomData: seq<#IConvertible>, + ?CustomDataEncoded: EncodedTypedArray, ?Groups: seq<#seq>, ?HoverInfo: StyleParam.HoverInfo, ?HoverLabel: Hoverlabel, @@ -58,12 +70,17 @@ type SankeyNodes() = ?Pad: int, ?Thickness: int, ?X: seq<#IConvertible>, - ?Y: seq<#IConvertible> + ?XEncoded: EncodedTypedArray, + ?Y: seq<#IConvertible>, + ?YEncoded: EncodedTypedArray ) = fun (sankeyNodes: SankeyNodes) -> sankeyNodes + |> DynObj.withOptionalPropertyBy "align" Align StyleParam.SankeyNodeAlign.convert |> DynObj.withOptionalProperty "color" Color + |> DynObj.withOptionalProperty "color" ColorEncoded |> DynObj.withOptionalProperty "customdata" CustomData + |> DynObj.withOptionalProperty "customdata" CustomDataEncoded |> DynObj.withOptionalProperty "groups" Groups |> DynObj.withOptionalPropertyBy "hoverinfo" HoverInfo StyleParam.HoverInfo.convert |> DynObj.withOptionalProperty "hoverlabel" HoverLabel @@ -73,7 +90,9 @@ type SankeyNodes() = |> DynObj.withOptionalProperty "pad" Pad |> DynObj.withOptionalProperty "thickness" Thickness |> DynObj.withOptionalProperty "x" X + |> DynObj.withOptionalProperty "x" XEncoded |> DynObj.withOptionalProperty "y" Y + |> DynObj.withOptionalProperty "y" YEncoded type SankeyLinkColorscale() = inherit DynamicObj() @@ -125,8 +144,10 @@ type SankeyLinks() = ( ?ArrowLen: int, ?Color: Color, + ?ColorEncoded: EncodedTypedArray, ?ColorScales: seq, ?CustomData: seq<#IConvertible>, + ?CustomDataEncoded: EncodedTypedArray, ?HoverInfo: StyleParam.HoverInfo, ?HoverLabel: Hoverlabel, ?HoverTemplate: string, @@ -134,16 +155,21 @@ type SankeyLinks() = ?Label: seq, ?Line: Line, ?Source: seq, + ?SourceEncoded: EncodedTypedArray, ?Target: seq, - ?Value: seq<#IConvertible> + ?TargetEncoded: EncodedTypedArray, + ?Value: seq<#IConvertible>, + ?ValueEncoded: EncodedTypedArray ) = SankeyLinks() |> SankeyLinks.style ( ?ArrowLen = ArrowLen, ?Color = Color, + ?ColorEncoded = ColorEncoded, ?ColorScales = ColorScales, ?CustomData = CustomData, + ?CustomDataEncoded = CustomDataEncoded, ?HoverInfo = HoverInfo, ?HoverLabel = HoverLabel, ?HoverTemplate = HoverTemplate, @@ -151,17 +177,21 @@ type SankeyLinks() = ?Label = Label, ?Line = Line, ?Source = Source, + ?SourceEncoded = SourceEncoded, ?Target = Target, - ?Value = Value - + ?TargetEncoded = TargetEncoded, + ?Value = Value, + ?ValueEncoded = ValueEncoded ) static member style ( ?ArrowLen: int, ?Color: Color, + ?ColorEncoded: EncodedTypedArray, ?ColorScales: seq, ?CustomData: seq<#IConvertible>, + ?CustomDataEncoded: EncodedTypedArray, ?HoverInfo: StyleParam.HoverInfo, ?HoverLabel: Hoverlabel, ?HoverTemplate: string, @@ -169,22 +199,30 @@ type SankeyLinks() = ?Label: seq, ?Line: Line, ?Source: seq, + ?SourceEncoded: EncodedTypedArray, ?Target: seq, - ?Value: seq<#IConvertible> + ?TargetEncoded: EncodedTypedArray, + ?Value: seq<#IConvertible>, + ?ValueEncoded: EncodedTypedArray ) = fun (sankeyLinks: SankeyLinks) -> sankeyLinks |> DynObj.withOptionalProperty "arrowlen" ArrowLen |> DynObj.withOptionalProperty "color" Color + |> DynObj.withOptionalProperty "color" ColorEncoded |> DynObj.withOptionalProperty "colorscales" ColorScales |> DynObj.withOptionalProperty "customdata" CustomData + |> DynObj.withOptionalProperty "customdata" CustomDataEncoded |> DynObj.withOptionalPropertyBy "hoverinfo" HoverInfo StyleParam.HoverInfo.convert |> DynObj.withOptionalProperty "hoverlabel" HoverLabel |> DynObj.withOptionalSingleOrMultiProperty "hovertemplate" (HoverTemplate, MultiHoverTemplate) |> DynObj.withOptionalProperty "label" Label |> DynObj.withOptionalProperty "line" Line |> DynObj.withOptionalProperty "source" Source + |> DynObj.withOptionalProperty "source" SourceEncoded |> DynObj.withOptionalProperty "target" Target + |> DynObj.withOptionalProperty "target" TargetEncoded |> DynObj.withOptionalProperty "value" Value + |> DynObj.withOptionalProperty "value" ValueEncoded diff --git a/tests/Common/FSharpTestBase/TestCharts/UpstreamFeatures/2.28.fs b/tests/Common/FSharpTestBase/TestCharts/UpstreamFeatures/2.28.fs index d3cc0e96..75f09e24 100644 --- a/tests/Common/FSharpTestBase/TestCharts/UpstreamFeatures/2.28.fs +++ b/tests/Common/FSharpTestBase/TestCharts/UpstreamFeatures/2.28.fs @@ -1043,3 +1043,62 @@ module ``Encoded typed arrays on carpet and domain traces`` = ) ) |> GenericChart.ofTraceObject true + +module ``Sankey node align`` = + + let ``Sankey with node align right`` = + let nodes = + SankeyNodes.init( + Label = ["A"; "B"; "C"], + Align = StyleParam.SankeyNodeAlign.Right + ) + let links = + SankeyLinks.init( + Source = [0; 1], + Target = [2; 2], + Value = [8; 4] + ) + Chart.Sankey(nodes, links, UseDefaults = false) + + let ``Sankey with node align via Chart overload`` = + Chart.Sankey( + nodeLabels = ["A"; "B"; "C"], + linkedNodeIds = [(0, 2); (1, 2)], + linkValues = [8; 4], + NodeAlign = StyleParam.SankeyNodeAlign.Left, + UseDefaults = false + ) + +module ``Sankey encoded node and link arrays`` = + + let ``Sankey with encoded node arrays`` = + let nodes = + SankeyNodes.init( + Label = ["A"; "B"; "C"], + ColorEncoded = EncodedTypedArray.ofFloat64Array [| 1.0; 2.0; 3.0 |], + CustomDataEncoded = EncodedTypedArray.ofFloat64Array [| 10.0; 20.0; 30.0 |], + XEncoded = EncodedTypedArray.ofFloat64Array [| 0.1; 0.5; 0.9 |], + YEncoded = EncodedTypedArray.ofFloat64Array [| 0.1; 0.5; 0.9 |] + ) + let links = + SankeyLinks.init( + Source = [0; 1], + Target = [2; 2], + Value = [8; 4] + ) + Chart.Sankey(nodes, links, UseDefaults = false) + + let ``Sankey with encoded link arrays`` = + let nodes = + SankeyNodes.init( + Label = ["A"; "B"; "C"] + ) + let links = + SankeyLinks.init( + SourceEncoded = EncodedTypedArray.ofInt32Array [| 0; 1 |], + TargetEncoded = EncodedTypedArray.ofInt32Array [| 2; 2 |], + ValueEncoded = EncodedTypedArray.ofFloat64Array [| 8.0; 4.0 |], + ColorEncoded = EncodedTypedArray.ofFloat64Array [| 1.0; 2.0 |], + CustomDataEncoded = EncodedTypedArray.ofFloat64Array [| 10.0; 20.0 |] + ) + Chart.Sankey(nodes, links, UseDefaults = false) diff --git a/tests/CoreTests/CoreTests/UpstreamFeatures/2.28.fs b/tests/CoreTests/CoreTests/UpstreamFeatures/2.28.fs index 40a907ef..e13574c8 100644 --- a/tests/CoreTests/CoreTests/UpstreamFeatures/2.28.fs +++ b/tests/CoreTests/CoreTests/UpstreamFeatures/2.28.fs @@ -905,3 +905,65 @@ module ``Encoded typed arrays on carpet and domain traces`` = ) ] ] + +module ``Sankey node align`` = + + [] + let ``Sankey node align tests`` = + testList "UpstreamFeatures.PlotlyJS_2_28" [ + testList "Sankey node align" [ + testCase "Sankey with node align right serializes align property on node object" (fun () -> + "\"node\":{\"align\":\"right\",\"label\":[\"A\",\"B\",\"C\"]}" + |> chartGeneratedContains ``Sankey node align``.``Sankey with node align right`` + ) + testCase "Sankey via Chart overload serializes align property on node object" (fun () -> + "\"node\":{\"align\":\"left\",\"label\":[\"A\",\"B\",\"C\"],\"line\":{}}" + |> chartGeneratedContains ``Sankey node align``.``Sankey with node align via Chart overload`` + ) + ] + ] + +module ``Sankey encoded node and link arrays`` = + + [] + let ``Sankey encoded node and link array tests`` = + testList "UpstreamFeatures.PlotlyJS_2_28" [ + testList "Sankey encoded node and link arrays" [ + testCase "Sankey node color is serialized as encoded object" (fun () -> + "\"color\":{\"bdata\":" + |> chartGeneratedContains ``Sankey encoded node and link arrays``.``Sankey with encoded node arrays`` + ) + testCase "Sankey node customdata is serialized as encoded object" (fun () -> + "\"customdata\":{\"bdata\":" + |> chartGeneratedContains ``Sankey encoded node and link arrays``.``Sankey with encoded node arrays`` + ) + testCase "Sankey node x is serialized as encoded object" (fun () -> + "\"x\":{\"bdata\":" + |> chartGeneratedContains ``Sankey encoded node and link arrays``.``Sankey with encoded node arrays`` + ) + testCase "Sankey node y is serialized as encoded object" (fun () -> + "\"y\":{\"bdata\":" + |> chartGeneratedContains ``Sankey encoded node and link arrays``.``Sankey with encoded node arrays`` + ) + testCase "Sankey link source is serialized as encoded object" (fun () -> + "\"source\":{\"bdata\":" + |> chartGeneratedContains ``Sankey encoded node and link arrays``.``Sankey with encoded link arrays`` + ) + testCase "Sankey link target is serialized as encoded object" (fun () -> + "\"target\":{\"bdata\":" + |> chartGeneratedContains ``Sankey encoded node and link arrays``.``Sankey with encoded link arrays`` + ) + testCase "Sankey link value is serialized as encoded object" (fun () -> + "\"value\":{\"bdata\":" + |> chartGeneratedContains ``Sankey encoded node and link arrays``.``Sankey with encoded link arrays`` + ) + testCase "Sankey link color is serialized as encoded object" (fun () -> + "\"color\":{\"bdata\":" + |> chartGeneratedContains ``Sankey encoded node and link arrays``.``Sankey with encoded link arrays`` + ) + testCase "Sankey link customdata is serialized as encoded object" (fun () -> + "\"customdata\":{\"bdata\":" + |> chartGeneratedContains ``Sankey encoded node and link arrays``.``Sankey with encoded link arrays`` + ) + ] + ] From f1e362a436191d4cc36ea033953e4b27cc214c01 Mon Sep 17 00:00:00 2001 From: Kevin Schneider Date: Thu, 16 Apr 2026 19:40:47 +0200 Subject: [PATCH 2/7] Add C# encoded array overloads for foundational chart types (Commit M) Adds encoded typed array convenience overloads to Plotly.NET.CSharp for the most commonly used chart types, completing the H3 phase of encoded array support: Chart2D.cs: - Chart.Scatter(xEncoded, yEncoded, mode, ...) - Chart.Bar(valuesEncoded, ...) - Chart.StackedBar(valuesEncoded, ...) - Chart.Column(valuesEncoded, ...) - Chart.StackedColumn(valuesEncoded, ...) - Chart.Heatmap(zEncoded, ?xEncoded, ?yEncoded, ...) - Chart.Histogram2D(xEncoded, yEncoded, ?zEncoded, ...) Chart3D.cs: - Chart.Scatter3D(xEncoded, yEncoded, zEncoded, mode, ...) Each overload delegates directly to the corresponding F# convenience overload in the relevant Chart*_*.Chart module. Base/Width SRTP params on Bar variants are exposed as generic type parameters BaseType/WidthType to satisfy F# compiled IL requirements from C#. Co-Authored-By: Claude Sonnet 4.6 --- src/Plotly.NET.CSharp/ChartAPI/Chart2D.cs | 407 ++++++++++++++++++++++ src/Plotly.NET.CSharp/ChartAPI/Chart3D.cs | 68 ++++ 2 files changed, 475 insertions(+) diff --git a/src/Plotly.NET.CSharp/ChartAPI/Chart2D.cs b/src/Plotly.NET.CSharp/ChartAPI/Chart2D.cs index c8766e6b..4d8e110b 100644 --- a/src/Plotly.NET.CSharp/ChartAPI/Chart2D.cs +++ b/src/Plotly.NET.CSharp/ChartAPI/Chart2D.cs @@ -2750,6 +2750,413 @@ public static GenericChart PointDensity( UseDefaults: UseDefaults.ToOption() ); + // ---- Encoded array overloads ---- + + /// Creates a Scatter plot from encoded x and y typed arrays. + /// Sets the x coordinates as an encoded typed array. + /// Sets the y coordinates as an encoded typed array. + /// Determines the drawing mode for this scatter trace. + /// If set to false, ignore the global default settings set in Defaults + public static GenericChart Scatter( + EncodedTypedArray xEncoded, + EncodedTypedArray yEncoded, + StyleParam.Mode mode, + Optional Name = default, + Optional ShowLegend = default, + Optional Opacity = default, + Optional> MultiOpacity = default, + Optional Text = default, + Optional> MultiText = default, + Optional TextPosition = default, + Optional> MultiTextPosition = default, + Optional MarkerColor = default, + Optional MarkerColorScale = default, + Optional MarkerOutline = default, + Optional MarkerSymbol = default, + Optional> MultiMarkerSymbol = default, + Optional Marker = default, + Optional LineColor = default, + Optional LineColorScale = default, + Optional LineWidth = default, + Optional LineDash = default, + Optional Line = default, + Optional AlignmentGroup = default, + Optional OffsetGroup = default, + Optional StackGroup = default, + Optional Orientation = default, + Optional GroupNorm = default, + Optional Fill = default, + Optional FillColor = default, + Optional FillPattern = default, + Optional UseWebGL = default, + Optional UseDefaults = default + ) + where TextType : IConvertible + => + Plotly.NET.Chart2D_Scatter.Chart.Scatter( + xEncoded: xEncoded, + yEncoded: yEncoded, + mode: mode, + Name: Name.ToOption(), + ShowLegend: ShowLegend.ToOption(), + Opacity: Opacity.ToOption(), + MultiOpacity: MultiOpacity.ToOption(), + Text: Text.ToOption(), + MultiText: MultiText.ToOption(), + TextPosition: TextPosition.ToOption(), + MultiTextPosition: MultiTextPosition.ToOption(), + MarkerColor: MarkerColor.ToOption(), + MarkerColorScale: MarkerColorScale.ToOption(), + MarkerOutline: MarkerOutline.ToOption(), + MarkerSymbol: MarkerSymbol.ToOption(), + MultiMarkerSymbol: MultiMarkerSymbol.ToOption(), + Marker: Marker.ToOption(), + LineColor: LineColor.ToOption(), + LineColorScale: LineColorScale.ToOption(), + LineWidth: LineWidth.ToOption(), + LineDash: LineDash.ToOption(), + Line: Line.ToOption(), + AlignmentGroup: AlignmentGroup.ToOption(), + OffsetGroup: OffsetGroup.ToOption(), + StackGroup: StackGroup.ToOption(), + Orientation: Orientation.ToOption(), + GroupNorm: GroupNorm.ToOption(), + Fill: Fill.ToOption(), + FillColor: FillColor.ToOption(), + FillPattern: FillPattern.ToOption(), + UseWebGL: UseWebGL.ToOption(), + UseDefaults: UseDefaults.ToOption() + ); + + /// Creates a bar chart from encoded values, with bars plotted horizontally. + /// Sets the bar lengths as an encoded typed array. + /// Sets the bar keys as an encoded typed array. + /// Sets where the bar base is drawn (in position axis units). + /// Sets the bar width (in position axis units) of all bars. + /// If set to false, ignore the global default settings set in Defaults + public static GenericChart Bar( + EncodedTypedArray valuesEncoded, + Optional KeysEncoded = default, + Optional Name = default, + Optional ShowLegend = default, + Optional Opacity = default, + Optional> MultiOpacity = default, + Optional Text = default, + Optional> MultiText = default, + Optional MarkerColor = default, + Optional MarkerColorScale = default, + Optional MarkerOutline = default, + Optional MarkerPatternShape = default, + Optional> MultiMarkerPatternShape = default, + Optional MarkerPattern = default, + Optional Marker = default, + Optional Base = default, + Optional Width = default, + Optional MultiWidthEncoded = default, + Optional TextPosition = default, + Optional> MultiTextPosition = default, + Optional UseDefaults = default + ) + where TextType : IConvertible + where BaseType : IConvertible + where WidthType : IConvertible + => + Plotly.NET.Chart2D_Bar.Chart.Bar( + valuesEncoded: valuesEncoded, + KeysEncoded: KeysEncoded.ToOption(), + Name: Name.ToOption(), + ShowLegend: ShowLegend.ToOption(), + Opacity: Opacity.ToOption(), + MultiOpacity: MultiOpacity.ToOption(), + Text: Text.ToOption(), + MultiText: MultiText.ToOption(), + MarkerColor: MarkerColor.ToOption(), + MarkerColorScale: MarkerColorScale.ToOption(), + MarkerOutline: MarkerOutline.ToOption(), + MarkerPatternShape: MarkerPatternShape.ToOption(), + MultiMarkerPatternShape: MultiMarkerPatternShape.ToOption(), + MarkerPattern: MarkerPattern.ToOption(), + Marker: Marker.ToOption(), + Base: Base.ToOption(), + Width: Width.ToOption(), + MultiWidthEncoded: MultiWidthEncoded.ToOption(), + TextPosition: TextPosition.ToOption(), + MultiTextPosition: MultiTextPosition.ToOption(), + UseDefaults: UseDefaults.ToOption() + ); + + /// Creates a stacked bar chart from encoded values, with bars plotted horizontally. + /// Sets the bar lengths as an encoded typed array. + /// Sets the bar keys as an encoded typed array. + /// Sets where the bar base is drawn (in position axis units). + /// Sets the bar width (in position axis units) of all bars. + /// If set to false, ignore the global default settings set in Defaults + public static GenericChart StackedBar( + EncodedTypedArray valuesEncoded, + Optional KeysEncoded = default, + Optional Name = default, + Optional ShowLegend = default, + Optional Opacity = default, + Optional> MultiOpacity = default, + Optional Text = default, + Optional> MultiText = default, + Optional MarkerColor = default, + Optional MarkerColorScale = default, + Optional MarkerOutline = default, + Optional MarkerPatternShape = default, + Optional> MultiMarkerPatternShape = default, + Optional MarkerPattern = default, + Optional Marker = default, + Optional Base = default, + Optional Width = default, + Optional MultiWidthEncoded = default, + Optional TextPosition = default, + Optional> MultiTextPosition = default, + Optional UseDefaults = default + ) + where TextType : IConvertible + where BaseType : IConvertible + where WidthType : IConvertible + => + Plotly.NET.Chart2D_Bar.Chart.StackedBar( + valuesEncoded: valuesEncoded, + KeysEncoded: KeysEncoded.ToOption(), + Name: Name.ToOption(), + ShowLegend: ShowLegend.ToOption(), + Opacity: Opacity.ToOption(), + MultiOpacity: MultiOpacity.ToOption(), + Text: Text.ToOption(), + MultiText: MultiText.ToOption(), + MarkerColor: MarkerColor.ToOption(), + MarkerColorScale: MarkerColorScale.ToOption(), + MarkerOutline: MarkerOutline.ToOption(), + MarkerPatternShape: MarkerPatternShape.ToOption(), + MultiMarkerPatternShape: MultiMarkerPatternShape.ToOption(), + MarkerPattern: MarkerPattern.ToOption(), + Marker: Marker.ToOption(), + Base: Base.ToOption(), + Width: Width.ToOption(), + MultiWidthEncoded: MultiWidthEncoded.ToOption(), + TextPosition: TextPosition.ToOption(), + MultiTextPosition: MultiTextPosition.ToOption(), + UseDefaults: UseDefaults.ToOption() + ); + + /// Creates a column chart from encoded values, with bars plotted vertically. + /// Sets the bar lengths as an encoded typed array. + /// Sets the bar keys as an encoded typed array. + /// Sets where the bar base is drawn (in position axis units). + /// Sets the bar width (in position axis units) of all bars. + /// If set to false, ignore the global default settings set in Defaults + public static GenericChart Column( + EncodedTypedArray valuesEncoded, + Optional KeysEncoded = default, + Optional Name = default, + Optional ShowLegend = default, + Optional Opacity = default, + Optional> MultiOpacity = default, + Optional Text = default, + Optional> MultiText = default, + Optional MarkerColor = default, + Optional MarkerColorScale = default, + Optional MarkerOutline = default, + Optional MarkerPatternShape = default, + Optional> MultiMarkerPatternShape = default, + Optional MarkerPattern = default, + Optional Marker = default, + Optional Base = default, + Optional Width = default, + Optional MultiWidthEncoded = default, + Optional TextPosition = default, + Optional> MultiTextPosition = default, + Optional UseDefaults = default + ) + where TextType : IConvertible + where BaseType : IConvertible + where WidthType : IConvertible + => + Plotly.NET.Chart2D_Bar.Chart.Column( + valuesEncoded: valuesEncoded, + KeysEncoded: KeysEncoded.ToOption(), + Name: Name.ToOption(), + ShowLegend: ShowLegend.ToOption(), + Opacity: Opacity.ToOption(), + MultiOpacity: MultiOpacity.ToOption(), + Text: Text.ToOption(), + MultiText: MultiText.ToOption(), + MarkerColor: MarkerColor.ToOption(), + MarkerColorScale: MarkerColorScale.ToOption(), + MarkerOutline: MarkerOutline.ToOption(), + MarkerPatternShape: MarkerPatternShape.ToOption(), + MultiMarkerPatternShape: MultiMarkerPatternShape.ToOption(), + MarkerPattern: MarkerPattern.ToOption(), + Marker: Marker.ToOption(), + Base: Base.ToOption(), + Width: Width.ToOption(), + MultiWidthEncoded: MultiWidthEncoded.ToOption(), + TextPosition: TextPosition.ToOption(), + MultiTextPosition: MultiTextPosition.ToOption(), + UseDefaults: UseDefaults.ToOption() + ); + + /// Creates a stacked column chart from encoded values, with bars plotted vertically. + /// Sets the bar lengths as an encoded typed array. + /// Sets the bar keys as an encoded typed array. + /// Sets where the bar base is drawn (in position axis units). + /// Sets the bar width (in position axis units) of all bars. + /// If set to false, ignore the global default settings set in Defaults + public static GenericChart StackedColumn( + EncodedTypedArray valuesEncoded, + Optional KeysEncoded = default, + Optional Name = default, + Optional ShowLegend = default, + Optional Opacity = default, + Optional> MultiOpacity = default, + Optional Text = default, + Optional> MultiText = default, + Optional MarkerColor = default, + Optional MarkerColorScale = default, + Optional MarkerOutline = default, + Optional MarkerPatternShape = default, + Optional> MultiMarkerPatternShape = default, + Optional MarkerPattern = default, + Optional Marker = default, + Optional Base = default, + Optional Width = default, + Optional MultiWidthEncoded = default, + Optional TextPosition = default, + Optional> MultiTextPosition = default, + Optional UseDefaults = default + ) + where TextType : IConvertible + where BaseType : IConvertible + where WidthType : IConvertible + => + Plotly.NET.Chart2D_Bar.Chart.StackedColumn( + valuesEncoded: valuesEncoded, + KeysEncoded: KeysEncoded.ToOption(), + Name: Name.ToOption(), + ShowLegend: ShowLegend.ToOption(), + Opacity: Opacity.ToOption(), + MultiOpacity: MultiOpacity.ToOption(), + Text: Text.ToOption(), + MultiText: MultiText.ToOption(), + MarkerColor: MarkerColor.ToOption(), + MarkerColorScale: MarkerColorScale.ToOption(), + MarkerOutline: MarkerOutline.ToOption(), + MarkerPatternShape: MarkerPatternShape.ToOption(), + MultiMarkerPatternShape: MultiMarkerPatternShape.ToOption(), + MarkerPattern: MarkerPattern.ToOption(), + Marker: Marker.ToOption(), + Base: Base.ToOption(), + Width: Width.ToOption(), + MultiWidthEncoded: MultiWidthEncoded.ToOption(), + TextPosition: TextPosition.ToOption(), + MultiTextPosition: MultiTextPosition.ToOption(), + UseDefaults: UseDefaults.ToOption() + ); + + /// Creates a heatmap from encoded z data and optional encoded axes. + /// Sets the z matrix as an encoded typed array. + /// Sets the x coordinates as an encoded typed array. + /// Sets the y coordinates as an encoded typed array. + /// If set to false, ignore the global default settings set in Defaults + public static GenericChart Heatmap( + EncodedTypedArray zEncoded, + Optional xEncoded = default, + Optional yEncoded = default, + Optional Name = default, + Optional ShowLegend = default, + Optional Opacity = default, + Optional XGap = default, + Optional YGap = default, + Optional Text = default, + Optional> MultiText = default, + Optional ColorBar = default, + Optional ColorScale = default, + Optional ShowScale = default, + Optional ReverseScale = default, + Optional ZSmooth = default, + Optional Transpose = default, + Optional UseWebGL = default, + Optional ReverseYAxis = default, + Optional UseDefaults = default + ) + where TextType : IConvertible + => + Plotly.NET.Chart2D_Heatmap.Chart.Heatmap( + zEncoded: zEncoded, + xEncoded: xEncoded.ToOption(), + yEncoded: yEncoded.ToOption(), + Name: Name.ToOption(), + ShowLegend: ShowLegend.ToOption(), + Opacity: Opacity.ToOption(), + XGap: XGap.ToOption(), + YGap: YGap.ToOption(), + Text: Text.ToOption(), + MultiText: MultiText.ToOption(), + ColorBar: ColorBar.ToOption(), + ColorScale: ColorScale.ToOption(), + ShowScale: ShowScale.ToOption(), + ReverseScale: ReverseScale.ToOption(), + ZSmooth: ZSmooth.ToOption(), + Transpose: Transpose.ToOption(), + UseWebGL: UseWebGL.ToOption(), + ReverseYAxis: ReverseYAxis.ToOption(), + UseDefaults: UseDefaults.ToOption() + ); + + /// Creates a 2D histogram from encoded x and y data. + /// Sets the x sample data as an encoded typed array. + /// Sets the y sample data as an encoded typed array. + /// Sets the z aggregation data as an encoded typed array. + /// If set to false, ignore the global default settings set in Defaults + public static GenericChart Histogram2D( + EncodedTypedArray xEncoded, + EncodedTypedArray yEncoded, + Optional zEncoded = default, + Optional Name = default, + Optional ShowLegend = default, + Optional Opacity = default, + Optional XGap = default, + Optional YGap = default, + Optional HistFunc = default, + Optional HistNorm = default, + Optional NBinsX = default, + Optional NBinsY = default, + Optional XBins = default, + Optional YBins = default, + Optional ColorBar = default, + Optional ColorScale = default, + Optional ShowScale = default, + Optional ReverseScale = default, + Optional ZSmooth = default, + Optional UseDefaults = default + ) + => + Plotly.NET.Chart2D_Histogram.Chart.Histogram2D( + xEncoded: xEncoded, + yEncoded: yEncoded, + zEncoded: zEncoded.ToOption(), + Name: Name.ToOption(), + ShowLegend: ShowLegend.ToOption(), + Opacity: Opacity.ToOption(), + XGap: XGap.ToOption(), + YGap: YGap.ToOption(), + HistFunc: HistFunc.ToOption(), + HistNorm: HistNorm.ToOption(), + NBinsX: NBinsX.ToOption(), + NBinsY: NBinsY.ToOption(), + XBins: XBins.ToOption(), + YBins: YBins.ToOption(), + ColorBar: ColorBar.ToOption(), + ColorScale: ColorScale.ToOption(), + ShowScale: ShowScale.ToOption(), + ReverseScale: ReverseScale.ToOption(), + ZSmooth: ZSmooth.ToOption(), + UseDefaults: UseDefaults.ToOption() + ); + }; } diff --git a/src/Plotly.NET.CSharp/ChartAPI/Chart3D.cs b/src/Plotly.NET.CSharp/ChartAPI/Chart3D.cs index a5b78bd4..0a269c60 100644 --- a/src/Plotly.NET.CSharp/ChartAPI/Chart3D.cs +++ b/src/Plotly.NET.CSharp/ChartAPI/Chart3D.cs @@ -845,6 +845,74 @@ public static GenericChart IsoSurface( Camera: Camera.ToOption(), UseDefaults: UseDefaults.ToOption() ); + // ---- Encoded array overloads ---- + + /// Creates a Scatter3D plot from encoded x, y, and z typed arrays. + /// Sets the x coordinates as an encoded typed array. + /// Sets the y coordinates as an encoded typed array. + /// Sets the z coordinates as an encoded typed array. + /// Determines the drawing mode for this scatter trace. + /// If set to false, ignore the global default settings set in Defaults + public static GenericChart Scatter3D( + EncodedTypedArray xEncoded, + EncodedTypedArray yEncoded, + EncodedTypedArray zEncoded, + StyleParam.Mode mode, + Optional Name = default, + Optional ShowLegend = default, + Optional Opacity = default, + Optional> MultiOpacity = default, + Optional Text = default, + Optional> MultiText = default, + Optional TextPosition = default, + Optional> MultiTextPosition = default, + Optional MarkerColor = default, + Optional MarkerColorScale = default, + Optional MarkerOutline = default, + Optional MarkerSymbol = default, + Optional> MultiMarkerSymbol = default, + Optional Marker = default, + Optional LineColor = default, + Optional LineColorScale = default, + Optional LineWidth = default, + Optional LineDash = default, + Optional Line = default, + Optional CameraProjectionType = default, + Optional Camera = default, + Optional Projection = default, + Optional UseDefaults = default + ) + where TextType : IConvertible + => + Plotly.NET.Chart3D_Scatter.Chart.Scatter3D( + xEncoded: xEncoded, + yEncoded: yEncoded, + zEncoded: zEncoded, + mode: mode, + Name: Name.ToOption(), + ShowLegend: ShowLegend.ToOption(), + Opacity: Opacity.ToOption(), + MultiOpacity: MultiOpacity.ToOption(), + Text: Text.ToOption(), + MultiText: MultiText.ToOption(), + TextPosition: TextPosition.ToOption(), + MultiTextPosition: MultiTextPosition.ToOption(), + MarkerColor: MarkerColor.ToOption(), + MarkerColorScale: MarkerColorScale.ToOption(), + MarkerOutline: MarkerOutline.ToOption(), + MarkerSymbol: MarkerSymbol.ToOption(), + MultiMarkerSymbol: MultiMarkerSymbol.ToOption(), + Marker: Marker.ToOption(), + LineColor: LineColor.ToOption(), + LineColorScale: LineColorScale.ToOption(), + LineWidth: LineWidth.ToOption(), + LineDash: LineDash.ToOption(), + Line: Line.ToOption(), + CameraProjectionType: CameraProjectionType.ToOption(), + Camera: Camera.ToOption(), + Projection: Projection.ToOption(), + UseDefaults: UseDefaults.ToOption() + ); } } From 1f7753696d02f68b796d64b54d5106d437b2a656 Mon Sep 17 00:00:00 2001 From: Kevin Schneider Date: Thu, 16 Apr 2026 19:46:36 +0200 Subject: [PATCH 3/7] Add ParallelCoord/ParallelCategories keyValuesEncoded convenience overloads (Commit L) Adds `Chart.ParallelCoord(keyValuesEncoded = ...)` and `Chart.ParallelCategories(keyValuesEncoded = ...)` convenience overloads to ChartDomain_Relations.fs. Each overload maps `seq` pairs to `Dimension.initParallel(Label = key, ValuesEncoded = encodedVals)`, delegating to the existing `dimensions` overload. Tests: 2 new assertions verifying dimension values serialize as `{"bdata":...}` encoded objects for both trace types. Plan update: Commit L complete (944 tests passing), Commit M (C# surface) marked done for foundational chart types. Co-Authored-By: Claude Sonnet 4.6 --- plans/PlotlyJS_2_28_Parity.md | 4 +- .../ChartDomain/ChartDomain_Relations.fs | 117 ++++++++++++++++++ .../TestCharts/UpstreamFeatures/2.28.fs | 20 +++ .../CoreTests/UpstreamFeatures/2.28.fs | 17 +++ 4 files changed, 156 insertions(+), 2 deletions(-) diff --git a/plans/PlotlyJS_2_28_Parity.md b/plans/PlotlyJS_2_28_Parity.md index 3ac34978..46f1f16e 100644 --- a/plans/PlotlyJS_2_28_Parity.md +++ b/plans/PlotlyJS_2_28_Parity.md @@ -30,11 +30,11 @@ The fixes are JS-runtime-only and do not require Plotly.NET changes — they are | Feature | F# Trace Layer | F# Chart API | C# Wrapper | Tests | Status | |---------|:-:|:-:|:-:|:-:|---| -| Encoded typed arrays | ✅ | ✅ | ❌ | ✅ 942 passing | H3 pending | +| Encoded typed arrays | ✅ | ✅ | ✅ (foundational) | ✅ 944 passing | H3 done | | Sankey node `align` | ✅ | ✅ | ❌ | ✅ | Done (Commit I) | | Virtual-WebGL | ❌ | N/A | N/A | ❌ | Not started | | Sankey encoded arrays (nodes + links) | ✅ | ✅ | ❌ | ✅ | Done (Commit K) | -| ParallelCoord/Categories `keyValuesEncoded` | ✅ Dimension-level | ❌ deferred | ❌ | ❌ | Deferred in H1-G | +| ParallelCoord/Categories `keyValuesEncoded` | ✅ | ✅ | ❌ | ✅ | Done (Commit L) | | Bundled plotly.js 2.28.0 | ✅ | — | — | — | Done | ## Remaining Work Packages diff --git a/src/Plotly.NET/ChartAPI/ChartDomain/ChartDomain_Relations.fs b/src/Plotly.NET/ChartAPI/ChartDomain/ChartDomain_Relations.fs index 4e2e4bdf..2d07fdea 100644 --- a/src/Plotly.NET/ChartAPI/ChartDomain/ChartDomain_Relations.fs +++ b/src/Plotly.NET/ChartAPI/ChartDomain/ChartDomain_Relations.fs @@ -141,6 +141,61 @@ module ChartDomain_Relations = ?UseDefaults = UseDefaults ) + /// + /// Creates a parallel coordinates plot from encoded dimension values. + /// + /// Parallel coordinates are a common way of visualizing and analyzing high-dimensional datasets. + /// + /// Sets the values for each dimension as (dimensionKey, encodedDimensionValues) pairs. + /// Sets the trace name. The trace name appear as the legend item and on hover + /// Sets the color of the lines that are connecting the datums on the dimensions + /// Sets the colorscale of the lines that are connecting the datums on the dimensions + /// Whether or not to show the colorbar of the lines that are connecting the datums on the dimensions + /// Whether or not to reverse the colorscale of the lines that are connecting the datums on the dimensions + /// Sets the lines that are connecting the datums on the dimensions (use this for more finegrained control than the other line-associated arguments). + /// Sets the angle of the labels with respect to the horizontal. + /// Sets the label font of this trace. + /// Specifies the location of the `label`. + /// Sets the range font of this trace. + /// Sets the tick font of this trace. + /// If set to false, ignore the global default settings set in `Defaults` + [] + static member ParallelCoord + ( + keyValuesEncoded: seq, + ?Name: string, + ?LineColor: Color, + ?LineColorScale: StyleParam.Colorscale, + ?ShowLineColorScale: bool, + ?ReverseLineColorScale: bool, + ?Line: Line, + ?LabelAngle: int, + ?LabelFont: Font, + ?LabelSide: StyleParam.Side, + ?RangeFont: Font, + ?TickFont: Font, + ?UseDefaults: bool + ) = + + let dims = + keyValuesEncoded |> Seq.map (fun (key, encodedVals) -> Dimension.initParallel (Label = key, ValuesEncoded = encodedVals)) + + Chart.ParallelCoord( + dimensions = dims, + ?Name = Name, + ?LineColor = LineColor, + ?LineColorScale = LineColorScale, + ?ShowLineColorScale = ShowLineColorScale, + ?ReverseLineColorScale = ReverseLineColorScale, + ?Line = Line, + ?LabelAngle = LabelAngle, + ?LabelFont = LabelFont, + ?LabelSide = LabelSide, + ?RangeFont = RangeFont, + ?TickFont = TickFont, + ?UseDefaults = UseDefaults + ) + /// /// Creates a parallel categories plot. /// @@ -289,6 +344,68 @@ module ChartDomain_Relations = ) |> GenericChart.ofTraceObject useDefaults + /// + /// Creates a parallel categories plot from encoded dimension values. + /// + /// The parallel categories diagram (also known as parallel sets or alluvial diagram) is a visualization of + /// multi-dimensional categorical data sets. + /// + /// Sets the values for each dimension as (dimensionKey, encodedDimensionValues) pairs. + /// Sets the trace name. The trace name appear as the legend item and on hover + /// The number of observations represented by each state. Defaults to 1 so that each state represents one observation + /// Sets the color of the lines that are connecting the datums on the dimensions + /// Sets the shape of the lines that are connecting the datums on the dimensions + /// Sets the colorscale of the lines that are connecting the datums on the dimensions + /// Whether or not to show the colorbar of the lines that are connecting the datums on the dimensions + /// Whether or not to reverse the colorscale of the lines that are connecting the datums on the dimensions + /// Sets the lines that are connecting the datums on the dimensions (use this for more finegrained control than the other line-associated arguments). + /// Sets the drag interaction mode for categories and dimensions. + /// Sort paths so that like colors are bundled together within each category. + /// Sets the path sorting algorithm. + /// Sets the label font of this trace. + /// Sets the tick font of this trace. + /// If set to false, ignore the global default settings set in `Defaults` + [] + static member ParallelCategories + ( + keyValuesEncoded: seq, + ?Name: string, + ?Counts: int, + ?LineColor: Color, + ?LineShape: StyleParam.Shape, + ?LineColorScale: StyleParam.Colorscale, + ?ShowLineColorScale: bool, + ?ReverseLineColorScale: bool, + ?Line: Line, + ?Arrangement: StyleParam.CategoryArrangement, + ?BundleColors: bool, + ?SortPaths: StyleParam.SortAlgorithm, + ?LabelFont: Font, + ?TickFont: Font, + ?UseDefaults: bool + ) = + + let dims = + keyValuesEncoded |> Seq.map (fun (key, encodedVals) -> Dimension.initParallel (Label = key, ValuesEncoded = encodedVals)) + + Chart.ParallelCategories( + dimensions = dims, + ?Name = Name, + ?Counts = Counts, + ?LineColor = LineColor, + ?LineShape = LineShape, + ?LineColorScale = LineColorScale, + ?ShowLineColorScale = ShowLineColorScale, + ?ReverseLineColorScale = ReverseLineColorScale, + ?Line = Line, + ?Arrangement = Arrangement, + ?BundleColors = BundleColors, + ?SortPaths = SortPaths, + ?LabelFont = LabelFont, + ?TickFont = TickFont, + ?UseDefaults = UseDefaults + ) + /// /// Creates a sankey diagram. /// diff --git a/tests/Common/FSharpTestBase/TestCharts/UpstreamFeatures/2.28.fs b/tests/Common/FSharpTestBase/TestCharts/UpstreamFeatures/2.28.fs index 75f09e24..c6f36718 100644 --- a/tests/Common/FSharpTestBase/TestCharts/UpstreamFeatures/2.28.fs +++ b/tests/Common/FSharpTestBase/TestCharts/UpstreamFeatures/2.28.fs @@ -1102,3 +1102,23 @@ module ``Sankey encoded node and link arrays`` = CustomDataEncoded = EncodedTypedArray.ofFloat64Array [| 10.0; 20.0 |] ) Chart.Sankey(nodes, links, UseDefaults = false) + +module ``ParallelCoord and ParallelCategories encoded dimensions`` = + + let ``ParallelCoord with encoded dimensions`` = + Chart.ParallelCoord( + keyValuesEncoded = [ + "A", EncodedTypedArray.ofFloat64Array [| 1.0; 2.0; 3.0 |] + "B", EncodedTypedArray.ofFloat64Array [| 4.0; 5.0; 6.0 |] + ], + UseDefaults = false + ) + + let ``ParallelCategories with encoded dimensions`` = + Chart.ParallelCategories( + keyValuesEncoded = [ + "X", EncodedTypedArray.ofInt32Array [| 0; 1; 0 |] + "Y", EncodedTypedArray.ofInt32Array [| 1; 0; 1 |] + ], + UseDefaults = false + ) diff --git a/tests/CoreTests/CoreTests/UpstreamFeatures/2.28.fs b/tests/CoreTests/CoreTests/UpstreamFeatures/2.28.fs index e13574c8..7eac97bb 100644 --- a/tests/CoreTests/CoreTests/UpstreamFeatures/2.28.fs +++ b/tests/CoreTests/CoreTests/UpstreamFeatures/2.28.fs @@ -967,3 +967,20 @@ module ``Sankey encoded node and link arrays`` = ) ] ] + +module ``ParallelCoord and ParallelCategories encoded dimensions`` = + + [] + let ``ParallelCoord and ParallelCategories encoded dimension tests`` = + testList "UpstreamFeatures.PlotlyJS_2_28" [ + testList "ParallelCoord and ParallelCategories encoded dimensions" [ + testCase "ParallelCoord dimension A values are serialized as encoded object" (fun () -> + "\"values\":{\"bdata\":" + |> chartGeneratedContains ``ParallelCoord and ParallelCategories encoded dimensions``.``ParallelCoord with encoded dimensions`` + ) + testCase "ParallelCategories dimension X values are serialized as encoded object" (fun () -> + "\"values\":{\"bdata\":" + |> chartGeneratedContains ``ParallelCoord and ParallelCategories encoded dimensions``.``ParallelCategories with encoded dimensions`` + ) + ] + ] From 263d7518fa3a02f17b4a35813767b545074e4c39 Mon Sep 17 00:00:00 2001 From: Kevin Schneider Date: Thu, 16 Apr 2026 19:48:49 +0200 Subject: [PATCH 4/7] Add documentation for encoded arrays and Sankey node alignment (Commit N) - Add docs/general/encoded-arrays.fsx: new General doc page covering EncodedTypedArray constructors, dtype table, and examples for Chart.Scatter, Chart.Bar, and Chart.Heatmap encoded overloads - Update docs/categorical-charts/sankey.fsx: add NodeAlign section showing Chart.Sankey with StyleParam.SankeyNodeAlign.Left - Update PlotlyJS_2_28_Parity.md: mark Virtual-WebGL as no surface needed (AdditionalHeadTags covers it), mark Commit N done, update test count to 944 Co-Authored-By: Claude Sonnet 4.6 --- docs/categorical-charts/sankey.fsx | 28 +++++ docs/general/encoded-arrays.fsx | 173 +++++++++++++++++++++++++++++ plans/PlotlyJS_2_28_Parity.md | 3 +- 3 files changed, 203 insertions(+), 1 deletion(-) create mode 100644 docs/general/encoded-arrays.fsx diff --git a/docs/categorical-charts/sankey.fsx b/docs/categorical-charts/sankey.fsx index b7d9a2fa..02e70ea0 100644 --- a/docs/categorical-charts/sankey.fsx +++ b/docs/categorical-charts/sankey.fsx @@ -79,3 +79,31 @@ sankey1 (***hide***) sankey1 |> GenericChart.toChartHTML (***include-it-raw***) + +(** +## Node alignment + +The `NodeAlign` parameter controls how nodes are aligned horizontally. The available options are +`Left`, `Right`, `Center`, and `Justify` (the default). + +Use the `NodeAlign` parameter on `Chart.Sankey` to apply alignment via the convenience overload, +or pass `Align` to `SankeyNodes.init` directly when building nodes manually: +*) + +let sankeyAligned = + Chart.Sankey( + nodeLabels = [ "Source A"; "Source B"; "Sink" ], + linkedNodeIds = [ 0, 2; 1, 2 ], + linkValues = [ 8; 4 ], + NodeAlign = StyleParam.SankeyNodeAlign.Left, + UseDefaults = false + ) + +(*** condition: ipynb ***) +#if IPYNB +sankeyAligned +#endif // IPYNB + +(***hide***) +sankeyAligned |> GenericChart.toChartHTML +(***include-it-raw***) diff --git a/docs/general/encoded-arrays.fsx b/docs/general/encoded-arrays.fsx new file mode 100644 index 00000000..6e64e52f --- /dev/null +++ b/docs/general/encoded-arrays.fsx @@ -0,0 +1,173 @@ +(** +--- +title: Encoded typed arrays +category: General +categoryindex: 1 +index: 10 +--- +*) + +(*** hide ***) + +(*** condition: prepare ***) +#r "nuget: Newtonsoft.JSON, 13.0.3" +#r "nuget: DynamicObj, 7.0.1" +#r "nuget: Giraffe.ViewEngine, 1.4.0" +#r "../../src/Plotly.NET/bin/Release/netstandard2.0/Plotly.NET.dll" + +Plotly.NET.Defaults.DefaultDisplayOptions <- + Plotly.NET.DisplayOptions.init (PlotlyJSReference = Plotly.NET.PlotlyJSReference.NoReference) + +(*** condition: ipynb ***) +#if IPYNB +#r "nuget: Plotly.NET, {{fsdocs-package-version}}" +#r "nuget: Plotly.NET.Interactive, {{fsdocs-package-version}}" +#endif // IPYNB + +(** +# Encoded typed arrays + +[![Binder]({{root}}img/badge-binder.svg)](https://mybinder.org/v2/gh/plotly/plotly.net/gh-pages?urlpath=/tree/home/jovyan/{{fsdocs-source-basename}}.ipynb)  +[![Notebook]({{root}}img/badge-notebook.svg)]({{root}}{{fsdocs-source-basename}}.ipynb) + +*Summary:* This page explains how to use `EncodedTypedArray` for efficient data transfer with plotly.js 2.28+. + +### Table of contents + +- [What are encoded typed arrays?](#What-are-encoded-typed-arrays) +- [Creating EncodedTypedArray values](#Creating-EncodedTypedArray-values) +- [Using encoded arrays with Scatter](#Using-encoded-arrays-with-Scatter) +- [Using encoded arrays with Bar and Column charts](#Using-encoded-arrays-with-Bar-and-Column-charts) +- [Using encoded arrays with Heatmap](#Using-encoded-arrays-with-Heatmap) + +## What are encoded typed arrays? + +plotly.js 2.28.0 introduced support for passing data arrays as **base64-encoded typed arrays** instead of plain JSON arrays. +This format (`bdata`/`dtype`/`shape`) is significantly more compact and faster to parse for large numeric datasets, +since it avoids the overhead of JSON number serialization. + +For example, a float64 array `[1.0, 2.0, 3.0]` transmitted as plain JSON looks like `[1.0,2.0,3.0]`, +while the encoded form is `{"bdata":"AAAAAAAA8D8AAAAAAAAAQA==...","dtype":"f8"}` — smaller and faster to deserialize in the browser. + +Plotly.NET exposes this via the `EncodedTypedArray` type. + +## Creating EncodedTypedArray values + +`EncodedTypedArray` can be constructed from any standard .NET typed array: +*) + +open Plotly.NET + +// Float64 (double) arrays — most common for continuous data +let xEncoded = EncodedTypedArray.ofFloat64Array [| 1.0; 2.0; 3.0; 4.0; 5.0 |] +let yEncoded = EncodedTypedArray.ofFloat64Array [| 2.0; 4.0; 1.0; 5.0; 3.0 |] + +// Int32 arrays — for integer data like indices or counts +let sourceEncoded = EncodedTypedArray.ofInt32Array [| 0; 1; 2 |] + +// Float32 arrays — smaller footprint when full precision is not needed +let valuesEncoded = EncodedTypedArray.ofFloat32Array [| 1.0f; 2.5f; 0.8f |] + +(** +Supported constructors: + +| Constructor | .NET type | plotly.js dtype | +|---|---|---| +| `EncodedTypedArray.ofFloat64Array` | `float[]` | `f8` (64-bit float) | +| `EncodedTypedArray.ofFloat32Array` | `float32[]` | `f4` (32-bit float) | +| `EncodedTypedArray.ofInt32Array` | `int[]` | `i4` (32-bit int) | +| `EncodedTypedArray.ofInt16Array` | `int16[]` | `i2` (16-bit int) | +| `EncodedTypedArray.ofInt8Array` | `sbyte[]` | `i1` (8-bit int) | +| `EncodedTypedArray.ofUInt32Array` | `uint32[]` | `u4` (unsigned 32-bit) | +| `EncodedTypedArray.ofUInt16Array` | `uint16[]` | `u2` (unsigned 16-bit) | +| `EncodedTypedArray.ofUInt8Array` | `byte[]` | `u1` (unsigned 8-bit) | + +## Using encoded arrays with Scatter + +The encoded convenience overload for `Chart.Scatter` takes `xEncoded` and `yEncoded` as required +positional arguments instead of plain `x`/`y` sequences: +*) + +let scatterEncoded = + Chart.Scatter( + xEncoded = EncodedTypedArray.ofFloat64Array [| 1.0; 2.0; 3.0; 4.0; 5.0 |], + yEncoded = EncodedTypedArray.ofFloat64Array [| 2.0; 4.0; 1.0; 5.0; 3.0 |], + mode = StyleParam.Mode.Markers, + Name = "encoded scatter", + UseDefaults = false + ) + +(*** condition: ipynb ***) +#if IPYNB +scatterEncoded +#endif // IPYNB + +(***hide***) +scatterEncoded |> GenericChart.toChartHTML +(***include-it-raw***) + +(** +The same encoded overload is available for `Chart.Point`, `Chart.Line`, `Chart.Bubble`, `Chart.Area`, `Chart.SplineArea`, and `Chart.StackedArea`. + +## Using encoded arrays with Bar and Column charts + +For bar and column charts, the main data array (`values`) is always required and encoded. +The keys array is optional: +*) + +let barEncoded = + Chart.Bar( + valuesEncoded = EncodedTypedArray.ofFloat64Array [| 5.0; 3.0; 7.0; 2.0 |], + KeysEncoded = EncodedTypedArray.ofInt32Array [| 0; 1; 2; 3 |], + Name = "encoded bar", + UseDefaults = false + ) + +(*** condition: ipynb ***) +#if IPYNB +barEncoded +#endif // IPYNB + +(***hide***) +barEncoded |> GenericChart.toChartHTML +(***include-it-raw***) + +(** +The same pattern applies to `Chart.Column`, `Chart.StackedBar`, and `Chart.StackedColumn`. + +## Using encoded arrays with Heatmap + +For heatmaps, the z matrix is required and encoded; x and y axes are optional and encoded: +*) + +let heatmapEncoded = + Chart.Heatmap( + zEncoded = EncodedTypedArray.ofFloat64Array [| 1.0; 2.0; 3.0; 4.0; 5.0; 6.0; 7.0; 8.0; 9.0 |], + Name = "encoded heatmap", + UseDefaults = false + ) + +(*** condition: ipynb ***) +#if IPYNB +heatmapEncoded +#endif // IPYNB + +(***hide***) +heatmapEncoded |> GenericChart.toChartHTML +(***include-it-raw***) + +(** +Note that for heatmaps the z data is passed as a flat 1D encoded array. plotly.js uses the `shape` field +(rows × columns) to interpret the layout. If you need to specify the shape, build the `EncodedTypedArray` +manually: + +```fsharp +// Explicit 3x3 shape +let z3x3 = + { EncodedTypedArray.ofFloat64Array [| 1.0..9.0 |] with Shape = Some "3,3" } +``` + +For more advanced usage including encoded arrays on 3D, domain, and map traces, see the trace-level +style modules (`Trace2DStyle`, `Trace3DStyle`, `TraceDomainStyle`, etc.) which accept `*Encoded` optional parameters +for most data-array fields. +*) diff --git a/plans/PlotlyJS_2_28_Parity.md b/plans/PlotlyJS_2_28_Parity.md index 46f1f16e..1fdd6a7d 100644 --- a/plans/PlotlyJS_2_28_Parity.md +++ b/plans/PlotlyJS_2_28_Parity.md @@ -32,9 +32,10 @@ The fixes are JS-runtime-only and do not require Plotly.NET changes — they are |---------|:-:|:-:|:-:|:-:|---| | Encoded typed arrays | ✅ | ✅ | ✅ (foundational) | ✅ 944 passing | H3 done | | Sankey node `align` | ✅ | ✅ | ❌ | ✅ | Done (Commit I) | -| Virtual-WebGL | ❌ | N/A | N/A | ❌ | Not started | +| Virtual-WebGL | N/A | N/A | N/A | N/A | No surface needed — use `DisplayOptions.AdditionalHeadTags` | | Sankey encoded arrays (nodes + links) | ✅ | ✅ | ❌ | ✅ | Done (Commit K) | | ParallelCoord/Categories `keyValuesEncoded` | ✅ | ✅ | ❌ | ✅ | Done (Commit L) | +| Documentation | ✅ | — | — | — | Done (Commit N) | | Bundled plotly.js 2.28.0 | ✅ | — | — | — | Done | ## Remaining Work Packages From 50d608eb76e727343b432fa2f9ff03b3e621d6fd Mon Sep 17 00:00:00 2001 From: Kevin Schneider Date: Thu, 16 Apr 2026 19:51:30 +0200 Subject: [PATCH 5/7] Update stale nuget references in docs scripts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - docs/3D-charts/3d-isosurface-plots.fsx: Newtonsoft.JSON 13.0.1 → 13.0.3, DynamicObj 2.0.0 → 7.0.1 - docs/general/image-export.fsx: PuppeteerSharp 9.0.2 → 24.40.0 All docs now consistently reference DynamicObj 7.0.1, Newtonsoft.JSON 13.0.3, Giraffe.ViewEngine 1.4.0, and PuppeteerSharp 24.40.0. Co-Authored-By: Claude Sonnet 4.6 --- docs/3D-charts/3d-isosurface-plots.fsx | 4 ++-- docs/general/image-export.fsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/3D-charts/3d-isosurface-plots.fsx b/docs/3D-charts/3d-isosurface-plots.fsx index c2243631..82ddcd12 100644 --- a/docs/3D-charts/3d-isosurface-plots.fsx +++ b/docs/3D-charts/3d-isosurface-plots.fsx @@ -10,8 +10,8 @@ index: 7 (*** hide ***) (*** condition: prepare ***) -#r "nuget: Newtonsoft.JSON, 13.0.1" -#r "nuget: DynamicObj, 2.0.0" +#r "nuget: Newtonsoft.JSON, 13.0.3" +#r "nuget: DynamicObj, 7.0.1" #r "nuget: Giraffe.ViewEngine, 1.4.0" #r "../../src/Plotly.NET/bin/Release/netstandard2.0/Plotly.NET.dll" diff --git a/docs/general/image-export.fsx b/docs/general/image-export.fsx index 5650d59e..167cce25 100644 --- a/docs/general/image-export.fsx +++ b/docs/general/image-export.fsx @@ -14,7 +14,7 @@ index: 2 #r "nuget: Newtonsoft.JSON, 13.0.3" #r "nuget: DynamicObj, 7.0.1" #r "nuget: Giraffe.ViewEngine, 1.4.0" -#r "nuget: PuppeteerSharp, 9.0.2" +#r "nuget: PuppeteerSharp, 24.40.0" #r "../../src/Plotly.NET/bin/Release/netstandard2.0/Plotly.NET.dll" #r "../../src/Plotly.NET.ImageExport/bin/Release/netstandard2.0/Plotly.NET.ImageExport.dll" From ff79a0322114d373758f27eb8ddfa9093c1bd4ca Mon Sep 17 00:00:00 2001 From: Kevin Schneider Date: Thu, 16 Apr 2026 22:07:26 +0200 Subject: [PATCH 6/7] update docs --- Plotly.NET.sln | 8 +- docs/_head.html | 2 +- docs/_template.ipynb | 0 docs/general/encoded-arrays.fsx | 124 +++++++++++++++++++-- tests/ConsoleApps/FSharpConsole/Program.fs | 16 +-- 5 files changed, 126 insertions(+), 24 deletions(-) delete mode 100644 docs/_template.ipynb diff --git a/Plotly.NET.sln b/Plotly.NET.sln index 1b00bd96..09303753 100644 --- a/Plotly.NET.sln +++ b/Plotly.NET.sln @@ -1,11 +1,12 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.31903.59 +# Visual Studio Version 18 +VisualStudioVersion = 18.5.11709.299 stable MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "project", "project", "{BF60BC93-E09B-4E5F-9D85-95A519479D54}" ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig + AGENTS.md = AGENTS.md CITATION.cff = CITATION.cff .config\dotnet-tools.json = .config\dotnet-tools.json LICENSE = LICENSE @@ -135,9 +136,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "04_distribution-charts", "0 docs\distribution-charts\histograms.fsx = docs\distribution-charts\histograms.fsx docs\distribution-charts\pareto-chart.fsx = docs\distribution-charts\pareto-chart.fsx docs\distribution-charts\point-density.fsx = docs\distribution-charts\point-density.fsx + docs\distribution-charts\residual.fsx = docs\distribution-charts\residual.fsx docs\distribution-charts\splom.fsx = docs\distribution-charts\splom.fsx docs\distribution-charts\violin-plots.fsx = docs\distribution-charts\violin-plots.fsx - docs\distribution-charts\residual.fsx = docs\distribution-charts\residual.fsx EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "01_chart-layout", "01_chart-layout", "{C7D0EF67-9A18-49DD-AC79-944E384BD8D0}" @@ -169,6 +170,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "00_general", "00_general", docs\general\chart-config.fsx = docs\general\chart-config.fsx docs\general\defaults.fsx = docs\general\defaults.fsx docs\general\display-options.fsx = docs\general\display-options.fsx + docs\general\encoded-arrays.fsx = docs\general\encoded-arrays.fsx docs\general\image-export.fsx = docs\general\image-export.fsx docs\general\multi-arguments.fsx = docs\general\multi-arguments.fsx docs\general\styling-markers.fsx = docs\general\styling-markers.fsx diff --git a/docs/_head.html b/docs/_head.html index 70ba3ddc..c8ed8f81 100644 --- a/docs/_head.html +++ b/docs/_head.html @@ -20,6 +20,6 @@ - + \ No newline at end of file diff --git a/docs/_template.ipynb b/docs/_template.ipynb deleted file mode 100644 index e69de29b..00000000 diff --git a/docs/general/encoded-arrays.fsx b/docs/general/encoded-arrays.fsx index 6e64e52f..2fccbe8f 100644 --- a/docs/general/encoded-arrays.fsx +++ b/docs/general/encoded-arrays.fsx @@ -39,6 +39,9 @@ Plotly.NET.Defaults.DefaultDisplayOptions <- - [Using encoded arrays with Scatter](#Using-encoded-arrays-with-Scatter) - [Using encoded arrays with Bar and Column charts](#Using-encoded-arrays-with-Bar-and-Column-charts) - [Using encoded arrays with Heatmap](#Using-encoded-arrays-with-Heatmap) +- [Using encoded arrays with 3D charts](#Using-encoded-arrays-with-3D-charts) +- [Using encoded arrays with statistical charts](#Using-encoded-arrays-with-statistical-charts) +- [Using encoded arrays for error bars and trace-level styling](#Using-encoded-arrays-for-error-bars-and-trace-level-styling) ## What are encoded typed arrays? @@ -119,8 +122,7 @@ let barEncoded = Chart.Bar( valuesEncoded = EncodedTypedArray.ofFloat64Array [| 5.0; 3.0; 7.0; 2.0 |], KeysEncoded = EncodedTypedArray.ofInt32Array [| 0; 1; 2; 3 |], - Name = "encoded bar", - UseDefaults = false + Name = "encoded bar" ) (*** condition: ipynb ***) @@ -137,12 +139,13 @@ The same pattern applies to `Chart.Column`, `Chart.StackedBar`, and `Chart.Stack ## Using encoded arrays with Heatmap -For heatmaps, the z matrix is required and encoded; x and y axes are optional and encoded: +For heatmaps, the z matrix is required and encoded; x and y axes are optional and encoded. +When `zEncoded` is given as a flat encoded array, `shape` must also be set so plotly.js can reconstruct the matrix: *) let heatmapEncoded = Chart.Heatmap( - zEncoded = EncodedTypedArray.ofFloat64Array [| 1.0; 2.0; 3.0; 4.0; 5.0; 6.0; 7.0; 8.0; 9.0 |], + zEncoded = EncodedTypedArray.ofFloat64Array([| 1.0; 2.0; 3.0; 4.0; 5.0; 6.0; 7.0; 8.0; 9.0 |], shape = [ 3; 3 ]), Name = "encoded heatmap", UseDefaults = false ) @@ -155,18 +158,121 @@ heatmapEncoded (***hide***) heatmapEncoded |> GenericChart.toChartHTML (***include-it-raw***) - (** Note that for heatmaps the z data is passed as a flat 1D encoded array. plotly.js uses the `shape` field -(rows × columns) to interpret the layout. If you need to specify the shape, build the `EncodedTypedArray` -manually: +(rows × columns) to interpret the layout, so `shape` must be specified: -```fsharp +``` // Explicit 3x3 shape let z3x3 = - { EncodedTypedArray.ofFloat64Array [| 1.0..9.0 |] with Shape = Some "3,3" } + EncodedTypedArray.ofFloat64Array([| 1.0 .. 9.0 |], shape = [ 3; 3 ]) ``` +The same `shape` requirement applies to other matrix-style traces such as `Chart.Surface`, `Chart.Contour`, +`Chart.Histogram2D`, and `Chart.Histogram2DContour`. + +## Using encoded arrays with 3D charts + +Encoded typed arrays work the same way on 3D traces. For example, `Chart.Scatter3D` accepts encoded x, y, and z coordinates: +*) + +let scatter3DEncoded = + Chart.Scatter3D( + xEncoded = EncodedTypedArray.ofFloat64Array [| 1.0; 2.0; 3.0 |], + yEncoded = EncodedTypedArray.ofFloat64Array [| 4.0; 5.0; 6.0 |], + zEncoded = EncodedTypedArray.ofFloat64Array [| 7.0; 8.0; 9.0 |], + mode = StyleParam.Mode.Markers, + Name = "encoded scatter3d", + UseDefaults = false + ) + +(*** condition: ipynb ***) +#if IPYNB +scatter3DEncoded +#endif // IPYNB + +(***hide***) +scatter3DEncoded |> GenericChart.toChartHTML +(***include-it-raw***) + +(** +For matrix-based 3D traces such as `Chart.Surface` and `Chart.Volume`, encoded arrays are also supported, +and `shape` must be set wherever plotly.js needs to reconstruct multi-dimensional data from a flat payload. + +## Using encoded arrays with statistical charts + +Distribution and statistical charts support encoded sample arrays as well. Here is a histogram example: +*) + +let histogramEncoded = + Chart.Histogram( + dataEncoded = EncodedTypedArray.ofFloat64Array [| 1.0; 2.0; 2.0; 3.0; 3.0; 3.0; 4.0 |], + orientation = StyleParam.Orientation.Vertical, + Name = "encoded histogram", + UseDefaults = false + ) + +(*** condition: ipynb ***) +#if IPYNB +histogramEncoded +#endif // IPYNB + +(***hide***) +histogramEncoded |> GenericChart.toChartHTML +(***include-it-raw***) + +(** +The same pattern works for `Chart.BoxPlot`, `Chart.Violin`, and finance-style traces such as +`Chart.OHLC` and `Chart.Candlestick`. + +## Using encoded arrays for error bars and trace-level styling + +Some features are available through trace-level styling rather than only through chart-root overloads. +This is especially useful when you want encoded error bars, encoded metadata arrays, or other advanced options: +*) + +open Plotly.NET.TraceObjects + +let scatterWithEncodedErrorBars = + let xErrorEncoded = EncodedTypedArray.ofFloat64Array [| 0.1; 0.2; 0.3 |] + let yErrorEncoded = EncodedTypedArray.ofFloat64Array [| 0.4; 0.5; 0.6 |] + let yErrorMinusEncoded = EncodedTypedArray.ofFloat64Array [| 0.3; 0.2; 0.1 |] + + Trace2D.initScatter( + Trace2DStyle.Scatter( + Name = "encoded scatter + error bars", + Mode = StyleParam.Mode.Lines_Markers, + XEncoded = EncodedTypedArray.ofFloat64Array [| 1.0; 2.0; 3.0 |], + YEncoded = EncodedTypedArray.ofFloat64Array [| 4.0; 5.0; 6.0 |], + XError = + Error.init( + Type = StyleParam.ErrorType.Data, + ArrayEncoded = xErrorEncoded + ), + YError = + Error.init( + Type = StyleParam.ErrorType.Data, + ArrayEncoded = yErrorEncoded, + ArrayminusEncoded = yErrorMinusEncoded + ) + ) + ) + |> GenericChart.ofTraceObject true + |> Chart.withDisplayOptionsStyle(PlotlyJSReference = PlotlyJSReference.NoReference) + +(*** condition: ipynb ***) +#if IPYNB +scatterWithEncodedErrorBars +#endif // IPYNB + +(***hide***) +scatterWithEncodedErrorBars |> GenericChart.toChartHTML +(***include-it-raw***) + +(** +The trace-style modules (`Trace2DStyle`, `Trace3DStyle`, `TraceDomainStyle`, and others) also accept encoded arrays +for many metadata fields such as ids, custom data, selected points, text, dimensions, and trace-specific attributes. + For more advanced usage including encoded arrays on 3D, domain, and map traces, see the trace-level style modules (`Trace2DStyle`, `Trace3DStyle`, `TraceDomainStyle`, etc.) which accept `*Encoded` optional parameters for most data-array fields. diff --git a/tests/ConsoleApps/FSharpConsole/Program.fs b/tests/ConsoleApps/FSharpConsole/Program.fs index 6ce7f451..ce100c59 100644 --- a/tests/ConsoleApps/FSharpConsole/Program.fs +++ b/tests/ConsoleApps/FSharpConsole/Program.fs @@ -3,16 +3,10 @@ open Plotly.NET [] let main _ = - let chartPointDensityEncodedHelpers = - Chart.PointDensity( - xEncoded = EncodedTypedArray.ofFloat64Array [| 0.0; 1.0; 2.0; 3.0; 4.0 |], - yEncoded = EncodedTypedArray.ofFloat64Array [| 0.0; 1.0; 0.5; 2.0; 1.5 |], - ContoursColoring = StyleParam.ContourColoring.Fill, - Name = "encoded point density helper", - UseDefaults = true - ) - |> Chart.withTitle "PointDensity: encoded x/y at chart helper layer" - - chartPointDensityEncodedHelpers |> Chart.show + Chart.Heatmap( + zEncoded = EncodedTypedArray.ofFloat64Array([| 1.0; 2.0; 3.0; 4.0; 5.0; 6.0; 7.0; 8.0; 9.0 |], shape = [ 3; 3 ]), + Name = "encoded heatmap", + UseDefaults = false + )|> Chart.show 0 From fd862365ae6c6a43acbc474c6dbba1abe2a4e845 Mon Sep 17 00:00:00 2001 From: Kevin Schneider Date: Thu, 16 Apr 2026 22:21:35 +0200 Subject: [PATCH 7/7] Complete plotly.js 2.28 C# parity bindings --- plans/PlotlyJS_2_28_Parity.md | 98 ++++----- src/Plotly.NET.CSharp/ChartAPI/ChartDomain.cs | 188 +++++++++++++++++- 2 files changed, 230 insertions(+), 56 deletions(-) diff --git a/plans/PlotlyJS_2_28_Parity.md b/plans/PlotlyJS_2_28_Parity.md index 1fdd6a7d..503df224 100644 --- a/plans/PlotlyJS_2_28_Parity.md +++ b/plans/PlotlyJS_2_28_Parity.md @@ -2,7 +2,7 @@ ## Summary -Plotly.NET has been targeting plotly.js 2.28.0 since the bundle was bumped in commit `62a96500`. The bulk of the work — encoded typed array support across all trace types and the F# Chart API — was completed in a long series of commits tracked in [EncodedArraySupport.md](EncodedArraySupport.md). This document identifies the **remaining gaps** needed for full 2.28.0 parity and lays out a plan to close them. +Plotly.NET has been targeting plotly.js 2.28.0 since the bundle was bumped in commit `62a96500`. The bulk of the work — encoded typed array support across all trace types and the F# Chart API — was completed in a long series of commits tracked in [EncodedArraySupport.md](EncodedArraySupport.md). The remaining C# domain-surface gaps were closed afterwards, so this document now serves as a completion record for the 2.28.0 parity work. ## plotly.js 2.28.0 Release Features @@ -26,23 +26,23 @@ Source: https://github.com/plotly/plotly.js/releases/tag/v2.28.0 The fixes are JS-runtime-only and do not require Plotly.NET changes — they are resolved by shipping the updated `plotly-2.28.0.min.js` bundle, which is already in place. -## Current Implementation Status +## Final Implementation Status | Feature | F# Trace Layer | F# Chart API | C# Wrapper | Tests | Status | |---------|:-:|:-:|:-:|:-:|---| -| Encoded typed arrays | ✅ | ✅ | ✅ (foundational) | ✅ 944 passing | H3 done | -| Sankey node `align` | ✅ | ✅ | ❌ | ✅ | Done (Commit I) | +| Encoded typed arrays | ✅ | ✅ | ✅ | ✅ 946 passing | Done | +| Sankey node `align` | ✅ | ✅ | ✅ | ✅ | Done | | Virtual-WebGL | N/A | N/A | N/A | N/A | No surface needed — use `DisplayOptions.AdditionalHeadTags` | -| Sankey encoded arrays (nodes + links) | ✅ | ✅ | ❌ | ✅ | Done (Commit K) | -| ParallelCoord/Categories `keyValuesEncoded` | ✅ | ✅ | ❌ | ✅ | Done (Commit L) | -| Documentation | ✅ | — | — | — | Done (Commit N) | +| Sankey encoded arrays (nodes + links) | ✅ | ✅ | ✅ | ✅ | Done | +| ParallelCoord/Categories `keyValuesEncoded` | ✅ | ✅ | ✅ | ✅ | Done | +| Documentation | ✅ | — | — | — | Done | | Bundled plotly.js 2.28.0 | ✅ | — | — | — | Done | -## Remaining Work Packages +## Implemented Items -### Commit I: Sankey node `align` property +### Sankey node `align` property -**Priority: High** — this is a user-visible new feature from 2.28.0 that has no Plotly.NET surface at all. +Implemented across the F# trace/chart layers and the C# wrapper. Scope: @@ -56,36 +56,21 @@ Files to change: - `src/Plotly.NET/CommonAbstractions/StyleParam.fs` — add `SankeyNodeAlign` DU - `src/Plotly.NET/Traces/ObjectAbstractions/Sankey.fs` — add `?Align` param to `SankeyNodes` - `src/Plotly.NET/ChartAPI/ChartDomain/ChartDomain_Relations.fs` — add `?NodeAlign` to `Chart.Sankey` -- `src/Plotly.NET.CSharp/ChartAPI/ChartDomain.cs` — add `NodeAlign` param to C# `Chart.Sankey` +- `src/Plotly.NET.CSharp/ChartAPI/ChartDomain.cs` — expose `NodeAlign` on the higher-level C# `Chart.Sankey` helper Tests: - add a test fixture in `tests/Common/FSharpTestBase/TestCharts/UpstreamFeatures/2.28.fs` - add assertions in `tests/CoreTests/CoreTests/UpstreamFeatures/2.28.fs` -- verify serialization produces `"node": { "align": "right" }` (or whichever value) +- verify serialization produces `"node": { "align": "right" }` -### Commit J: Virtual-WebGL config option +### Virtual-WebGL -**Priority: Low** — niche feature for pages with many WebGL contexts. Plotly.NET charts are typically rendered one-at-a-time in HTML, but notebook and multi-chart scenarios could benefit. +No dedicated Plotly.NET surface was needed. Users can inject the `virtual-webgl` script through `DisplayOptions.AdditionalHeadTags`, which is sufficient for the plotly.js integration model. -Scope: - -- determine how plotly.js exposes this option (likely a config-level flag or a separate script include) -- if it is a config option: add it to `Config.fs` as `?VirtualWebGL: bool` -- if it is a script include: add support in `DisplayOptions` to inject the virtual-webgl script tag before the plotly.js bundle -- add minimal test coverage - -Files to change (depending on mechanism): - -- `src/Plotly.NET/Config/Config.fs` — if config-level -- `src/Plotly.NET/DisplayOptions/DisplayOptions.fs` — if script-level -- corresponding C# surface if applicable +### Sankey encoded arrays at Chart API level -Note: This requires further investigation of the plotly.js implementation ([#6784](https://github.com/plotly/plotly.js/pull/6784)) to determine the exact integration point. May be purely client-side and not need a Plotly.NET wrapper at all. - -### Commit K: Sankey encoded arrays at Chart API level - -**Priority: Medium** — trace-level encoded support already exists; this is about exposing it ergonomically at the Chart API. +Implemented on the trace layer, F# chart layer, and exposed to C# through the wrapper surface. Scope: @@ -99,11 +84,12 @@ Files to change: - `src/Plotly.NET/Traces/ObjectAbstractions/Sankey.fs` - `src/Plotly.NET/ChartAPI/ChartDomain/ChartDomain_Relations.fs` +- `src/Plotly.NET.CSharp/ChartAPI/ChartDomain.cs` - test fixtures and assertions in upstream 2.28 test files -### Commit L: ParallelCoord / ParallelCategories `keyValuesEncoded` convenience +### ParallelCoord / ParallelCategories `keyValuesEncoded` convenience -**Priority: Low** — `Dimension.initParallel` already supports `ValuesEncoded`, so users can build encoded dimensions manually. This is a convenience-only gap. +Implemented on the F# chart layer and mirrored to C#. Scope: @@ -111,9 +97,13 @@ Scope: - delegate to existing `Dimension.initParallel(ValuesEncoded = ...)` internally - add tests -### Commit M: C# surface projection (Phase H3) +### C# surface projection (Phase H3) + +Implemented. The foundational encoded chart roots were added earlier, and the missing domain helpers were completed by adding: -**Priority: High** — blocks any C# consumer from using encoded arrays through the idiomatic API. +- C# `Chart.Sankey(..., NodeAlign, ...)` +- C# `Chart.ParallelCoord(IEnumerable<(string, EncodedTypedArray)> keyValuesEncoded, ...)` +- C# `Chart.ParallelCategories(IEnumerable<(string, EncodedTypedArray)> keyValuesEncoded, ...)` Scope: @@ -121,7 +111,7 @@ Scope: - focus on foundational chart roots first: - `Chart.Scatter`, `Chart.Bar`, `Chart.Histogram`, `Chart.Heatmap`, `Chart.Scatter3D`, etc. - avoid duplicating every convenience overload — only add C# encoded overloads for the most commonly used chart types -- add C# interop tests in `tests/CoreTests/CSharpInteroperabilityTests/` +- validate through the existing core build/test targets Files to change: @@ -133,36 +123,34 @@ Files to change: - `src/Plotly.NET.CSharp/ChartAPI/ChartSmith.cs` - `src/Plotly.NET.CSharp/ChartAPI/ChartTernary.cs` - `src/Plotly.NET.CSharp/ChartAPI/ChartCarpet.cs` -- test files in `tests/CoreTests/CSharpInteroperabilityTests/` +- documentation and release notes -### Commit N: Documentation updates +### Documentation updates -**Priority: Medium** — users need to know encoded arrays exist. +Implemented. Scope: - add a new doc page (e.g. `docs/general/encoded-arrays.fsx`) showing how to use `EncodedTypedArray` with common chart types - update the Sankey docs page to show the `align` property -- mention 2.28.0 features in RELEASE_NOTES.md for the upcoming version +- mention 2.28.0 features in `RELEASE_NOTES.md` for the upcoming version -## Recommended Commit Order +## Outcome -| Order | Commit | Description | Dependency | -|:---:|:---:|---|---| -| 1 | **I** | Sankey `align` property | None | -| 2 | **K** | Sankey encoded Chart API | None (can parallel with I) | -| 3 | **M** | C# encoded surface (H3) | H2 complete ✅ | -| 4 | **L** | ParallelCoord/Categories encoded convenience | H1-D-Splom complete ✅ | -| 5 | **J** | Virtual-WebGL (investigation + possible impl) | None | -| 6 | **N** | Documentation | After I, K, M | +Plotly.NET now has full planned parity with plotly.js 2.28.0: -Commits I and K are independent and can be developed in parallel. Commit M (C# surface) is the largest remaining effort. Commit J requires upstream investigation and may turn out to be unnecessary for the Plotly.NET surface. +- bundled plotly.js 2.28.0 runtime +- encoded typed arrays across trace layers and chart APIs +- Sankey node alignment +- encoded Sankey node/link support +- encoded ParallelCoord/ParallelCategories convenience overloads +- C# wrapper coverage for the parity surface +- docs and release notes ## Verification -After all commits: +Verified in repo: -- `.\build.cmd runTestsAll` should pass -- all upstream 2.28 test fixtures should be green -- C# interop tests should cover at least the foundational encoded chart roots -- manual console samples should render correctly in a browser +- `.\build.cmd runTestsCore` passes +- upstream 2.28 fixtures are present and green in the core suite +- the C# wrapper builds successfully with the completed domain bindings diff --git a/src/Plotly.NET.CSharp/ChartAPI/ChartDomain.cs b/src/Plotly.NET.CSharp/ChartAPI/ChartDomain.cs index d4805812..a3fe126e 100644 --- a/src/Plotly.NET.CSharp/ChartAPI/ChartDomain.cs +++ b/src/Plotly.NET.CSharp/ChartAPI/ChartDomain.cs @@ -4,6 +4,7 @@ using Plotly.NET.TraceObjects; using System; using System.Collections.Generic; +using System.Linq; using System.Runtime.InteropServices; @@ -569,6 +570,56 @@ public static GenericChart ParallelCoord( UseDefaults: UseDefaults.ToOption() ); + /// + /// Creates a parallel coordinates plot from encoded dimension values. + /// + /// Parallel coordinates are a common way of visualizing and analyzing high-dimensional datasets. + /// + /// Sets the values for each dimension as (dimensionKey, encodedDimensionValues) pairs. + /// Sets the trace name. The trace name appear as the legend item and on hover + /// Sets the color of the lines that are connecting the datums on the dimensions + /// Sets the colorscale of the lines that are connecting the datums on the dimensions + /// Whether or not to show the colorbar of the lines that are connecting the datums on the dimensions + /// Whether or not to reverse the colorscale of the lines that are connecting the datums on the dimensions + /// Sets the lines that are connecting the datums on the dimensions (use this for more finegrained control than the other line-associated arguments). + /// Sets the angle of the labels with respect to the horizontal. + /// Sets the label font of this trace. + /// Specifies the location of the `label`. + /// Sets the range font of this trace. + /// Sets the tick font of this trace. + /// If set to false, ignore the global default settings set in `Defaults` + public static GenericChart ParallelCoord( + IEnumerable<(string, EncodedTypedArray)> keyValuesEncoded, + Optional Name = default, + Optional LineColor = default, + Optional LineColorScale = default, + Optional ShowLineColorScale = default, + Optional ReverseLineColorScale = default, + Optional Line = default, + Optional LabelAngle = default, + Optional LabelFont = default, + Optional LabelSide = default, + Optional RangeFont = default, + Optional TickFont = default, + Optional UseDefaults = default + ) + => + Plotly.NET.ChartDomain_Relations.Chart.ParallelCoord( + keyValuesEncoded: keyValuesEncoded.Select(kv => kv.ToTuple()), + Name: Name.ToOption(), + LineColor: LineColor.ToOption(), + LineColorScale: LineColorScale.ToOption(), + ShowLineColorScale: ShowLineColorScale.ToOption(), + ReverseLineColorScale: ReverseLineColorScale.ToOption(), + Line: Line.ToOption(), + LabelAngle: LabelAngle.ToOption(), + LabelFont: LabelFont.ToOption(), + LabelSide: LabelSide.ToOption(), + RangeFont: RangeFont.ToOption(), + TickFont: TickFont.ToOption(), + UseDefaults: UseDefaults.ToOption() + ); + /// /// Creates a parallel categories plot. /// @@ -628,6 +679,63 @@ public static GenericChart ParallelCategories( UseDefaults: UseDefaults.ToOption() ); + /// + /// Creates a parallel categories plot from encoded dimension values. + /// + /// The parallel categories diagram (also known as parallel sets or alluvial diagram) is a visualization of + /// multi-dimensional categorical data sets. + /// + /// Sets the values for each dimension as (dimensionKey, encodedDimensionValues) pairs. + /// Sets the trace name. The trace name appear as the legend item and on hover + /// The number of observations represented by each state. Defaults to 1 so that each state represents one observation + /// Sets the color of the lines that are connecting the datums on the dimensions + /// Sets the shape of the lines that are connecting the datums on the dimensions + /// Sets the colorscale of the lines that are connecting the datums on the dimensions + /// Whether or not to show the colorbar of the lines that are connecting the datums on the dimensions + /// Whether or not to reverse the colorscale of the lines that are connecting the datums on the dimensions + /// Sets the lines that are connecting the datums on the dimensions (use this for more finegrained control than the other line-associated arguments). + /// Sets the drag interaction mode for categories and dimensions. If `perpendicular`, the categories can only move along a line perpendicular to the paths. If `freeform`, the categories can freely move on the plane. If `fixed`, the categories and dimensions are stationary. + /// Sort paths so that like colors are bundled together within each category. + /// Sets the path sorting algorithm. If `forward`, sort paths based on dimension categories from left to right. If `backward`, sort paths based on dimensions categories from right to left. + /// Sets the label font of this trace. + /// Sets the tick font of this trace. + /// If set to false, ignore the global default settings set in `Defaults` + public static GenericChart ParallelCategories( + IEnumerable<(string, EncodedTypedArray)> keyValuesEncoded, + Optional Name = default, + Optional Counts = default, + Optional LineColor = default, + Optional LineShape = default, + Optional LineColorScale = default, + Optional ShowLineColorScale = default, + Optional ReverseLineColorScale = default, + Optional Line = default, + Optional Arrangement = default, + Optional BundleColors = default, + Optional SortPaths = default, + Optional LabelFont = default, + Optional TickFont = default, + Optional UseDefaults = default + ) + => + Plotly.NET.ChartDomain_Relations.Chart.ParallelCategories( + keyValuesEncoded: keyValuesEncoded.Select(kv => kv.ToTuple()), + Name: Name.ToOption(), + Counts: Counts.ToOption(), + LineColor: LineColor.ToOption(), + LineShape: LineShape.ToOption(), + LineColorScale: LineColorScale.ToOption(), + ShowLineColorScale: ShowLineColorScale.ToOption(), + ReverseLineColorScale: ReverseLineColorScale.ToOption(), + Line: Line.ToOption(), + Arrangement: Arrangement.ToOption(), + BundleColors: BundleColors.ToOption(), + SortPaths: SortPaths.ToOption(), + LabelFont: LabelFont.ToOption(), + TickFont: TickFont.ToOption(), + UseDefaults: UseDefaults.ToOption() + ); + /// /// Creates a sankey diagram. /// @@ -672,6 +780,85 @@ public static GenericChart Sankey( UseDefaults: UseDefaults.ToOption() ); + /// + /// Creates a sankey diagram. + /// + /// A Sankey diagram is a flow diagram, in which the width of arrows is proportional to the flow quantity. + /// + /// Sets the labels of the nodes in the sankey diagram + /// (source, target) tuples which indicate connected nodes. These values map to the index in `nodeLabels` + /// The values for the links in the sankey diagram. + /// Sets the color of the nodes in the sankey diagram. + /// Sets the color of the node outlines in the sankey diagram. + /// Sets the outline width of the nodes in the sankey diagram. + /// Sets the thickness of the nodes in the sankey diagram. + /// Sets groups of nodes. Each group is defined by an array with the indices of the nodes it contains. Multiple groups can be specified. + /// Sets the color of the links in the sankey diagram. + /// Sets the colorscale of the links in the sankey diagram. + /// Sets the outline color of the links in the sankey diagram. + /// Sets the outline width of the links in the sankey diagram. + /// Sets the labels of the links in the sankey diagram. + /// Sets the trace name. The trace name appear as the legend item and on hover. + /// Assigns id labels to each datum. + /// Sets the orientation of the Sankey diagram. + /// Sets the text font of this trace. + /// If value is `snap` (the default), the node arrangement is assisted by automatic snapping of elements to preserve space between nodes specified via `nodepad`. If value is `perpendicular`, the nodes can only move along a line perpendicular to the flow. If value is `freeform`, the nodes can freely move on the plane. If value is `fixed`, the nodes are stationary. + /// Sets the horizontal alignment of the nodes in the Sankey diagram. If value is `justify` (the default), the nodes are spread to fill the width. If value is `left`, `right`, or `center`, the nodes are aligned accordingly. + /// Sets the value formatting rule using d3 formatting mini-languages which are very similar to those in Python. For numbers, see: https://github.com/d3/d3-format/tree/v1.4.5#d3-format. + /// Adds a unit to follow the value in the hover tooltip. Add a space if a separation is necessary from the value. + /// If set to false, ignore the global default settings set in `Defaults` + public static GenericChart Sankey( + IEnumerable nodeLabels, + IEnumerable<(int, int)> linkedNodeIds, + IEnumerable linkValues, + Optional NodeColor = default, + Optional NodeOutlineColor = default, + Optional NodeOutlineWidth = default, + Optional NodeThickness = default, + Optional>> NodeGroups = default, + Optional LinkColor = default, + Optional> LinkColorScales = default, + Optional LinkOutlineColor = default, + Optional LinkOutlineWidth = default, + Optional> LinkLabels = default, + Optional Name = default, + Optional> Ids = default, + Optional Orientation = default, + Optional TextFont = default, + Optional Arrangement = default, + Optional NodeAlign = default, + Optional ValueFormat = default, + Optional ValueSuffix = default, + Optional UseDefaults = default + ) + where LinkValuesType : IConvertible + where IdsType : IConvertible + => + Plotly.NET.ChartDomain_Relations.Chart.Sankey, IdsType>( + nodeLabels, + linkedNodeIds.Select(link => link.ToTuple()), + linkValues, + NodeColor.ToOption(), + NodeOutlineColor.ToOption(), + NodeOutlineWidth.ToOption(), + NodeThickness.ToOption(), + NodeGroups.ToOption(), + LinkColor.ToOption(), + LinkColorScales.ToOption(), + LinkOutlineColor.ToOption(), + LinkOutlineWidth.ToOption(), + LinkLabels.ToOption(), + Name.ToOption(), + Ids.ToOption(), + Orientation.ToOption(), + TextFont.ToOption(), + Arrangement.ToOption(), + NodeAlign.ToOption(), + ValueFormat.ToOption(), + ValueSuffix.ToOption(), + UseDefaults.ToOption() + ); + /// /// Creates a table. /// @@ -886,4 +1073,3 @@ public static GenericChart Icicle