Skip to content

Commit c249de1

Browse files
committed
Fix parallel chart styling options (#477)
1 parent c5fa9db commit c249de1

7 files changed

Lines changed: 113 additions & 4 deletions

File tree

‎docs/categorical-charts/parallel-categories.fsx‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ parcats |> GenericChart.toChartHTML
6363
## More styled example
6464
6565
This example shows the usage of some of the styling options using `Chart.ParallelCategories`.
66+
`LineShape = StyleParam.Shape.HSpline` draws horizontal spline paths between categories, while `TickFont` controls the category tick labels.
6667
For even more styling control, use the respective TraceStyle function `TraceDomainStyle.ParallelCategories`
6768
*)
6869

@@ -76,6 +77,8 @@ let parcatsStyled =
7677
dimensions = dims,
7778
LineColor = Color.fromColorScaleValues [ 0; 1; 2; 2; 1; 1; 0; 0 ], // These values map to the last category axis, meaning [AAA => 0; AAB = 1; AAC => 2]
7879
LineColorScale = StyleParam.Colorscale.Viridis,
80+
LineShape = StyleParam.Shape.HSpline,
81+
TickFont = Font.init(Family = StyleParam.FontFamily.Arial, Size = 14.),
7982
BundleColors = false
8083
)
8184

‎src/Plotly.NET/CommonAbstractions/StyleParams.fs‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3056,7 +3056,7 @@ module StyleParam =
30563056
member this.Convert() =
30573057
this |> MarkerSymbol.toInteger |> string |> box
30583058

3059-
/// Determines the line shape. With "spline" the lines are drawn using spline interpolation. The other available values correspond to step-wise line shapes.
3059+
/// Determines the line shape. "spline" uses spline interpolation; "hspline" draws horizontal spline paths in parallel categories plots. "hv", "vh", "hvh", and "vhv" are step-wise shapes. Supported values depend on the trace type.
30603060
[<RequireQualifiedAccess>]
30613061
type Shape =
30623062
| Linear
@@ -3065,6 +3065,7 @@ module StyleParam =
30653065
| Vh
30663066
| Hvh
30673067
| Vhv
3068+
| HSpline
30683069

30693070
static member toString =
30703071
function
@@ -3074,6 +3075,7 @@ module StyleParam =
30743075
| Vh -> "vh"
30753076
| Hvh -> "hvh"
30763077
| Vhv -> "vhv"
3078+
| HSpline -> "hspline"
30773079

30783080
static member convert = Shape.toString >> box
30793081
override this.ToString() = this |> Shape.toString

‎src/Plotly.NET/RELEASE_NOTES.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ As a consequence, the html dsl dependency switches back from `Giraffe.ViewEngine
1212

1313
- Bump bundled plotly.js to **2.28.0**
1414

15+
- [#477](https://github.com/plotly/Plotly.NET/issues/477): Fix tick-font serialization for parallel categories and parallel coordinates charts, and add `StyleParam.Shape.HSpline` for horizontal spline paths in parallel categories plots.
16+
1517
- [#441](https://github.com/plotly/Plotly.NET/issues/441): **Encoded typed array support** — plotly.js 2.28 introduced a base64 representation for numeric arrays. Plotly.NET supports it for selected trace fields and chart constructors:
1618

1719
- New `EncodedTypedArray` type (in `Plotly.NET`) carrying a base64 payload (`bdata`), a dtype tag (`dtype`), and an optional shape for multi-dimensional data. Supported dtypes: `Float64`, `Float32`, `Int32`, `UInt32`, `Int16`, `UInt16`, `Int8`, `UInt8`, `UInt8Clamped`.

‎src/Plotly.NET/Traces/TraceDomain.fs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -674,7 +674,7 @@ type TraceDomainStyle() =
674674
|> DynObj.withOptionalProperty "labelfont" LabelFont
675675
|> DynObj.withOptionalProperty "labelside" LabelSide
676676
|> DynObj.withOptionalProperty "rangefont" RangeFont
677-
|> DynObj.withOptionalProperty "tickfont " TickFont
677+
|> DynObj.withOptionalProperty "tickfont" TickFont
678678
|> DynObj.withOptionalProperty "uirevision" UIRevision
679679

680680
/// <summary>
@@ -745,7 +745,7 @@ type TraceDomainStyle() =
745745
|> DynObj.withOptionalPropertyBy "sortpaths" SortPaths StyleParam.SortAlgorithm.convert
746746
|> DynObj.withOptionalPropertyBy "hoveron" Hoveron StyleParam.HoverOn.convert
747747
|> DynObj.withOptionalProperty "labelfont" LabelFont
748-
|> DynObj.withOptionalProperty "tickfont " TickFont
748+
|> DynObj.withOptionalProperty "tickfont" TickFont
749749
|> DynObj.withOptionalProperty "uirevision" UIRevision
750750

751751
/// <summary>

‎tests/Common/FSharpTestBase/TestCharts/ChartDomainTestCharts.fs‎

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,13 @@ module ParallelCoord =
187187
UseDefaults = false
188188
)
189189

190+
let ``Parallel coordinates with tick font`` =
191+
Chart.ParallelCoord(
192+
keyValues = [ "A", [ 1; 2 ]; "B", [ 3; 4 ] ],
193+
TickFont = Font.init(Family = StyleParam.FontFamily.Arial, Size = 14., Color = Color.fromString "purple"),
194+
UseDefaults = false
195+
)
196+
190197
module ParallelCategories =
191198

192199
let ``Simple parallel categories chart`` =
@@ -219,6 +226,14 @@ module ParallelCategories =
219226
UseDefaults = false
220227
)
221228

229+
let ``Parallel categories with horizontal splines and tick font`` =
230+
Chart.ParallelCategories(
231+
keyValues = [ "A", [ "a"; "b" ]; "B", [ "c"; "d" ] ],
232+
LineShape = StyleParam.Shape.HSpline,
233+
TickFont = Font.init(Family = StyleParam.FontFamily.Arial, Size = 14., Color = Color.fromString "purple"),
234+
UseDefaults = false
235+
)
236+
222237
module Sankey =
223238

224239
let ``Styled sankey chart`` =
@@ -478,4 +493,4 @@ module Icicle =
478493
SectionOutlineColor = Color.fromKeyword Black,
479494
Tiling = IcicleTiling.init(Flip = StyleParam.TilingFlip.XY),
480495
UseDefaults = false
481-
)
496+
)

‎tests/CoreTests/CoreTests/HTMLCodegen/ChartDomain.fs‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,10 @@ module ParallelCoord =
125125
testCase "Parallel coordinates styled layout" ( fun () ->
126126
emptyLayout ParallelCoord.``Styled parallel coordinates chart``
127127
);
128+
testCase "Parallel coordinates tick font" ( fun () ->
129+
"""var data = [{"type":"parcoords","dimensions":[{"label":"A","values":[1,2],"axis":{}},{"label":"B","values":[3,4],"axis":{}}],"line":{},"tickfont":{"family":"Arial","size":14.0,"color":"purple"}}];"""
130+
|> chartGeneratedContains ParallelCoord.``Parallel coordinates with tick font``
131+
);
128132
]
129133
]
130134

@@ -147,6 +151,10 @@ module ParallelCategories =
147151
testCase "Parallel categories styled layout" ( fun () ->
148152
emptyLayout ParallelCategories.``Styled parallel categories chart``
149153
);
154+
testCase "Parallel categories horizontal splines and tick font" ( fun () ->
155+
"""var data = [{"type":"parcats","dimensions":[{"label":"A","values":["a","b"],"axis":{}},{"label":"B","values":["c","d"],"axis":{}}],"line":{"shape":"hspline"},"tickfont":{"family":"Arial","size":14.0,"color":"purple"}}];"""
156+
|> chartGeneratedContains ParallelCategories.``Parallel categories with horizontal splines and tick font``
157+
);
150158
]
151159
]
152160

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
using System;
2+
using Plotly.NET;
3+
using Plotly.NET.TraceObjects;
4+
using Xunit;
5+
using Chart = Plotly.NET.CSharp.Chart;
6+
7+
namespace CSharp.Tests.HtmlCodegen.ChartDomain;
8+
9+
public class ParallelStylingTests
10+
{
11+
[Theory]
12+
[InlineData("ParallelCoord")]
13+
[InlineData("ParallelCoordEncoded")]
14+
[InlineData("ParallelCategories")]
15+
[InlineData("ParallelCategoriesEncoded")]
16+
public void ConstructorsPreserveTickFontAndSupportedLineShape(string chartName)
17+
{
18+
var (chart, expectedData) = CreateCase(chartName);
19+
20+
TestUtils.ChartGeneratedSectionEquals(chart, ChartMarkupSection.Data, expectedData);
21+
}
22+
23+
private static Dimension Dimension(string label, int[] values) =>
24+
Plotly.NET.TraceObjects.Dimension.initParallel<string, string, int, int>(
25+
ConstraintRange: default,
26+
Label: label,
27+
MultiSelect: default,
28+
Name: default,
29+
Range: default,
30+
TemplateItemName: default,
31+
TickFormat: default,
32+
TickText: default,
33+
Tickvals: default,
34+
Values: values,
35+
ValuesEncoded: default,
36+
Visible: default
37+
);
38+
39+
// Baselines generated with tools/chart-baseline-generation/generate-chart-markup.fsx.
40+
private static (GenericChart Chart, string Data) CreateCase(string chartName)
41+
{
42+
var font = Font.init(
43+
Family: StyleParam.FontFamily.Arial,
44+
Size: 14.0,
45+
Color: Color.fromString("purple")
46+
);
47+
var dimensions = new[] { Dimension("A", new[] { 1, 2 }), Dimension("B", new[] { 3, 4 }) };
48+
var encoded = new[]
49+
{
50+
("A", EncodedTypedArray.ofInt32Array(new[] { 1, 2 }, shape: default)),
51+
("B", EncodedTypedArray.ofInt32Array(new[] { 3, 4 }, shape: default))
52+
};
53+
54+
return chartName switch
55+
{
56+
"ParallelCoord" => (
57+
Chart.ParallelCoord(dimensions: dimensions, TickFont: font, UseDefaults: false),
58+
"""var data = [{"type":"parcoords","dimensions":[{"label":"A","values":[1,2],"axis":{}},{"label":"B","values":[3,4],"axis":{}}],"line":{},"tickfont":{"family":"Arial","size":14.0,"color":"purple"}}];"""
59+
),
60+
"ParallelCoordEncoded" => (
61+
Chart.ParallelCoord(keyValuesEncoded: encoded, TickFont: font, UseDefaults: false),
62+
"""var data = [{"type":"parcoords","dimensions":[{"label":"A","values":{"bdata":"AQAAAAIAAAA=","dtype":"i4"},"axis":{}},{"label":"B","values":{"bdata":"AwAAAAQAAAA=","dtype":"i4"},"axis":{}}],"line":{},"tickfont":{"family":"Arial","size":14.0,"color":"purple"}}];"""
63+
),
64+
"ParallelCategories" => (
65+
Chart.ParallelCategories(
66+
dimensions: dimensions, LineShape: StyleParam.Shape.HSpline,
67+
TickFont: font, UseDefaults: false),
68+
"""var data = [{"type":"parcats","dimensions":[{"label":"A","values":[1,2],"axis":{}},{"label":"B","values":[3,4],"axis":{}}],"line":{"shape":"hspline"},"tickfont":{"family":"Arial","size":14.0,"color":"purple"}}];"""
69+
),
70+
"ParallelCategoriesEncoded" => (
71+
Chart.ParallelCategories(
72+
keyValuesEncoded: encoded, LineShape: StyleParam.Shape.HSpline,
73+
TickFont: font, UseDefaults: false),
74+
"""var data = [{"type":"parcats","dimensions":[{"label":"A","values":{"bdata":"AQAAAAIAAAA=","dtype":"i4"},"axis":{}},{"label":"B","values":{"bdata":"AwAAAAQAAAA=","dtype":"i4"},"axis":{}}],"line":{"shape":"hspline"},"tickfont":{"family":"Arial","size":14.0,"color":"purple"}}];"""
75+
),
76+
_ => throw new ArgumentOutOfRangeException(nameof(chartName), chartName, null)
77+
};
78+
}
79+
}

0 commit comments

Comments
 (0)