diff --git a/src/Plotly.NET/ChartAPI/Chart.fs b/src/Plotly.NET/ChartAPI/Chart.fs index 77e4c593..151c896e 100644 --- a/src/Plotly.NET/ChartAPI/Chart.fs +++ b/src/Plotly.NET/ChartAPI/Chart.fs @@ -3072,15 +3072,26 @@ type Chart = ch |> Chart.withConfig config) - - //============================================================================================================== //================================= More complicated composite methods ========================================= //============================================================================================================== /// - /// Creates a subplot grid with the given dimensions (nRows x nCols) for the input charts. + /// Creates a subplot grid with the given dimensions (nRows x nCols) for the input charts. The default row order is from top to bottom. + /// + /// For each input chart, a corresponding subplot cell is created in the grid. The following limitations apply to the individual grid cells: + /// + /// - only one pair of 2D cartesian axes is allowed per cell. If there are multiple x or y axes on an input chart, the first one is used, and the rest is discarded (meaning, it is removed from the combined layout). + /// if you need multiple axes per grid cell, create a custom grid by manually creating axes with custom domains instead. + /// The new id of the axes corresponds to the number of the grid cell, e.g. the third grid cell will contain xaxis3 and yaxis3 + /// + /// - For other subplot layouts (Cartesian3D, Polar, Ternary, Geo, Mapbox, Smith), the same rule applies: only one subplot per grid cell, the first one is used, the rest is discarded. + /// The new id of the subplot layout corresponds to the number of the grid cell, e.g. the third grid cell will contain scene3 etc. + /// + /// - The Domain of traces that calculate their position by domain only (e.g. Pie traces) are replaced by a domain pointing to the new grid position. + /// + /// - If SubPlotTitles are provided, they are used as the titles of the individual cells in ascending order. If the number of titles is less than the number of subplots, the remaining subplots are left without a title. /// /// The number of rows in the grid. If you provide a 2D `subplots` array or a `yaxes` array, its length is used as the default. But it's also possible to have a different length, if you want to leave a row at the end for non-cartesian subplots. /// The number of columns in the grid. If you provide a 2D `subplots` array, the length of its longest row is used as the default. If you give an `xaxes` array, its length is used as the default. But it's also possible to have a different length, if you want to leave a row at the end for non-cartesian subplots. @@ -3213,6 +3224,13 @@ type Chart = let yAxis = layout.TryGetTypedValue "yaxis" |> Option.defaultValue (LinearAxis.init ()) + let allXAxes = Layout.getXAxes layout |> Seq.map fst + let allYAxes = Layout.getYAxes layout |> Seq.map fst + + // remove all axes from layout. Only cartesian axis in each dimension is supported per grid cell, and leaving anything else on this layout may lead to property name clashes on combine. + allXAxes |> Seq.iter (fun propName -> layout.Remove(propName) |> ignore) + allYAxes |> Seq.iter (fun propName -> layout.Remove(propName) |> ignore) + let xAnchor, yAnchor = if hasSharedAxes then colIndex, rowIndex //set axis anchors according to grid coordinates @@ -3223,13 +3241,7 @@ type Chart = |> Chart.withAxisAnchor (xAnchor, yAnchor) // set adapted axis anchors |> Chart.withXAxis (xAxis, (StyleParam.SubPlotId.XAxis(i + 1))) // set previous axis with adapted id (one individual axis for each subplot, whether or not they will be used later) |> Chart.withYAxis (yAxis, (StyleParam.SubPlotId.YAxis(i + 1))) // set previous axis with adapted id (one individual axis for each subplot, whether or not they will be used later) - |> GenericChart.mapLayout (fun l -> - if i > 0 then - // remove default axes from consecutive charts, otherwise they will override the first one - l.Remove("xaxis") |> ignore - l.Remove("yaxis") |> ignore - l) | TraceID.Cartesian3D -> let scene = @@ -3237,6 +3249,11 @@ type Chart = |> Option.defaultValue (Scene.init ()) |> Scene.style (Domain = LayoutObjects.Domain.init (Row = rowIndex - 1, Column = colIndex - 1)) + let allScenes = Layout.getScenes layout |> Seq.map fst + + // remove all scenes from layout. Only one scene is supported per grid cell, and leaving anything else on this layout may lead to property name clashes on combine. + allScenes |> Seq.iter (fun propName -> layout.Remove(propName) |> ignore) + let sceneAnchor = StyleParam.SubPlotId.Scene(i + 1) @@ -3250,6 +3267,11 @@ type Chart = |> Option.defaultValue (Polar.init ()) |> Polar.style (Domain = LayoutObjects.Domain.init (Row = rowIndex - 1, Column = colIndex - 1)) + let allPolars = Layout.getPolars layout |> Seq.map fst + + // remove all polar subplots from layout. Only one polar subplot is supported per grid cell, and leaving anything else on this layout may lead to property name clashes on combine. + allPolars |> Seq.iter (fun propName -> layout.Remove(propName) |> ignore) + let polarAnchor = StyleParam.SubPlotId.Polar(i + 1) @@ -3264,6 +3286,11 @@ type Chart = layout.TryGetTypedValue "smith" |> Option.defaultValue (Smith.init ()) |> Smith.style (Domain = LayoutObjects.Domain.init (Row = rowIndex - 1, Column = colIndex - 1)) + + let allSmiths = Layout.getSmiths layout |> Seq.map fst + + // remove all smith subplots from layout. Only one smith subplot is supported per grid cell, and leaving anything else on this layout may lead to property name clashes on combine. + allSmiths |> Seq.iter (fun propName -> layout.Remove(propName) |> ignore) let polarAnchor = StyleParam.SubPlotId.Smith(i + 1) @@ -3279,12 +3306,18 @@ type Chart = |> Option.defaultValue (Geo.init ()) |> Geo.style (Domain = LayoutObjects.Domain.init (Row = rowIndex - 1, Column = colIndex - 1)) + let allGeos = Layout.getGeos layout |> Seq.map fst + + // remove all geo subplots from layout. Only one geo subplot is supported per grid cell, and leaving anything else on this layout may lead to property name clashes on combine. + allGeos |> Seq.iter (fun propName -> layout.Remove(propName) |> ignore) + let geoAnchor = StyleParam.SubPlotId.Geo(i + 1) gChart |> GenericChart.mapTrace (fun t -> t :?> TraceGeo |> TraceGeoStyle.SetGeo geoAnchor :> Trace) |> Chart.withGeo (geo, (i + 1)) + | TraceID.Mapbox -> let mapbox = layout.TryGetTypedValue "mapbox" @@ -3293,6 +3326,14 @@ type Chart = Domain = LayoutObjects.Domain.init (Row = rowIndex - 1, Column = colIndex - 1) ) + let allMapboxes = Layout.getMapboxes layout |> Seq.map fst + + // remove all mapbox subplots from layout. Only one mapbox subplot is supported per grid cell, and leaving anything else on this layout may lead to property name clashes on combine. + allMapboxes |> Seq.iter (fun propName -> layout.Remove(propName) |> ignore) + + let geoAnchor = + StyleParam.SubPlotId.Geo(i + 1) + let mapboxAnchor = StyleParam.SubPlotId.Mapbox(i + 1) @@ -3300,13 +3341,6 @@ type Chart = |> GenericChart.mapTrace (fun t -> t :?> TraceMapbox |> TraceMapboxStyle.SetMapbox mapboxAnchor :> Trace) |> Chart.withMapbox (mapbox, (i + 1)) - | TraceID.Domain -> - let newDomain = - LayoutObjects.Domain.init (Row = rowIndex - 1, Column = colIndex - 1) - - gChart - |> GenericChart.mapTrace (fun t -> - t :?> TraceDomain |> TraceDomainStyle.SetDomain newDomain :> Trace) | TraceID.Ternary -> @@ -3317,13 +3351,29 @@ type Chart = Domain = LayoutObjects.Domain.init (Row = rowIndex - 1, Column = colIndex - 1) ) + let allTernaries = Layout.getTernaries layout |> Seq.map fst + + // remove all ternary subplots from layout. Only one ternary subplot is supported per grid cell, and leaving anything else on this layout may lead to property name clashes on combine. + allTernaries |> Seq.iter (fun propName -> layout.Remove(propName) |> ignore) + let ternaryAnchor = StyleParam.SubPlotId.Ternary(i + 1) gChart |> GenericChart.mapTrace (fun t -> t :?> TraceTernary |> TraceTernaryStyle.SetTernary ternaryAnchor :> Trace) - |> Chart.withTernary (ternary, (i + 1))) + |> Chart.withTernary (ternary, (i + 1)) + + | TraceID.Domain -> + + // no need to remove existing domains, as only one domain can exist on the original layout. Just replace it. + let newDomain = + LayoutObjects.Domain.init (Row = rowIndex - 1, Column = colIndex - 1) + + gChart + |> GenericChart.mapTrace (fun t -> + t :?> TraceDomain |> TraceDomainStyle.SetDomain newDomain :> Trace) + ) |> Chart.combine |> Chart.withAnnotations(subPlotTitleAnnotations, Append=true) |> Chart.withLayoutGrid ( @@ -3349,6 +3399,19 @@ type Chart = /// ATTENTION: when the individual rows do not have the same amount of charts, they will be filled with dummy charts TO THE RIGHT. /// /// prevent this behaviour by using Chart.Invisible at the cells that should be empty. + /// + /// For each input chart, a corresponding subplot cell is created in the grid. The following limitations apply to the individual grid cells: + /// + /// - only one pair of 2D cartesian axes is allowed per cell. If there are multiple x or y axes on an input chart, the first one is used, and the rest is discarded (meaning, it is removed from the combined layout). + /// if you need multiple axes per grid cell, create a custom grid by manually creating axes with custom domains instead. + /// The new id of the axes corresponds to the number of the grid cell, e.g. the third grid cell will contain xaxis3 and yaxis3 + /// + /// - For other subplot layouts (Cartesian3D, Polar, Ternary, Geo, Mapbox, Smith), the same rule applies: only one subplot per grid cell, the first one is used, the rest is discarded. + /// The new id of the subplot layout corresponds to the number of the grid cell, e.g. the third grid cell will contain scene3 etc. + /// + /// - The Domain of traces that calculate their position by domain only (e.g. Pie traces) are replaced by a domain pointing to the new grid position. + /// + /// - If SubPlotTitles are provided, they are used as the titles of the individual cells in ascending order. If the number of titles is less than the number of subplots, the remaining subplots are left without a title. /// /// A collection of titles for the individual subplots. /// The font of the subplot titles @@ -3453,6 +3516,19 @@ type Chart = ) /// Creates a chart stack (a subplot grid with one column) from the input charts. + /// + /// For each input chart, a corresponding subplot cell is created in the column. The following limitations apply to the individual grid cells: + /// + /// - only one pair of 2D cartesian axes is allowed per cell. If there are multiple x or y axes on an input chart, the first one is used, and the rest is discarded (meaning, it is removed from the combined layout). + /// if you need multiple axes per grid cell, create a custom grid by manually creating axes with custom domains instead. + /// The new id of the axes corresponds to the number of the grid cell, e.g. the third grid cell will contain xaxis3 and yaxis3 + /// + /// - For other subplot layouts (Cartesian3D, Polar, Ternary, Geo, Mapbox, Smith), the same rule applies: only one subplot per grid cell, the first one is used, the rest is discarded. + /// The new id of the subplot layout corresponds to the number of the grid cell, e.g. the third grid cell will contain scene3 etc. + /// + /// - The Domain of traces that calculate their position by domain only (e.g. Pie traces) are replaced by a domain pointing to the new grid position. + /// + /// - If SubPlotTitles are provided, they are used as the titles of the individual cells in ascending order. If the number of titles is less than the number of subplots, the remaining subplots are left without a title. /// /// A collection of titles for the individual subplots. /// The font of the subplot titles diff --git a/tests/Common/FSharpTestBase/FSharpTestBase.fsproj b/tests/Common/FSharpTestBase/FSharpTestBase.fsproj index a1230196..7617a492 100644 --- a/tests/Common/FSharpTestBase/FSharpTestBase.fsproj +++ b/tests/Common/FSharpTestBase/FSharpTestBase.fsproj @@ -12,6 +12,7 @@ + diff --git a/tests/Common/FSharpTestBase/TestCharts/FeatureAdditions/Fix_3d_GridPosition.fs b/tests/Common/FSharpTestBase/TestCharts/FeatureAdditions/Fix_3d_GridPosition.fs new file mode 100644 index 00000000..eb16bcb4 --- /dev/null +++ b/tests/Common/FSharpTestBase/TestCharts/FeatureAdditions/Fix_3d_GridPosition.fs @@ -0,0 +1,32 @@ +module Fix_3d_GridPosition + +open Plotly.NET +open Plotly.NET.TraceObjects +open Plotly.NET.LayoutObjects +open DynamicObj + +// https://github.com/plotly/Plotly.NET/issues/413 + +module ``Remove all existing subplots from individual charts on grid creation #413`` = + + let ``2x2 grid with only 3D charts and correct scene positioning`` = + [ + Chart.Point3D(xyz = [1,3,2], UseDefaults = false) + Chart.Point3D(xyz = [1,3,2], UseDefaults = false) + Chart.Point3D(xyz = [1,3,2], UseDefaults = false) + Chart.Point3D(xyz = [1,3,2], UseDefaults = false) + ] + |> Chart.Grid(2,2, SubPlotTitles = ["1";"2";"3";"4"]) + + let ``2x2 grid chart creation ignores other scenes`` = + [ + Chart.Point3D(xyz = [1,3,2], UseDefaults = false) + |> Chart.withScene(Scene.init(), Id = 2) + Chart.Point3D(xyz = [1,3,2], UseDefaults = false) + |> Chart.withScene(Scene.init(), Id = 420) + Chart.Point3D(xyz = [1,3,2], UseDefaults = false) + |> Chart.withScene(Scene.init(), Id = 69) + Chart.Point3D(xyz = [1,3,2], UseDefaults = false) + |> Chart.withScene(Scene.init(), Id = 1337) + ] + |> Chart.Grid(2,2, SubPlotTitles = ["1";"2";"3";"4"]) \ No newline at end of file diff --git a/tests/ConsoleApps/FSharpConsole/Program.fs b/tests/ConsoleApps/FSharpConsole/Program.fs index 46665bcb..09bf2e52 100644 --- a/tests/ConsoleApps/FSharpConsole/Program.fs +++ b/tests/ConsoleApps/FSharpConsole/Program.fs @@ -11,21 +11,22 @@ open Newtonsoft.Json [] let main args = + let x = [1.; 2.; 3.; 4.; 5.; 6.; 7.; 8.; 9.; 10.; ] + let y = [2.; 1.5; 5.; 1.5; 3.; 2.5; 2.5; 1.5; 3.5; 1.] [ - Chart.Point(xy = [1,2; 2,3], UseDefaults = false) - Chart.PointTernary(abc = [1,2,3; 2,3,4], UseDefaults = false) - Chart.Heatmap(zData = [[1; 2];[3; 4]], ShowScale=false, UseDefaults = false) - Chart.Point3D(xyz = [1,3,2], UseDefaults = false) - Chart.PointMapbox(lonlat = [1,2], UseDefaults = false) |> Chart.withMapbox(Mapbox.init(Style = StyleParam.MapboxStyle.OpenStreetMap)) - [ - // you can use nested combined charts, but they have to have the same trace type (Cartesian2D in this case) - let y = [2.; 1.5; 5.; 1.5; 2.; 2.5; 2.1; 2.5; 1.5; 1.;2.; 1.5; 5.; 1.5; 3.; 2.5; 2.5; 1.5; 3.5; 1.] - Chart.BoxPlot(X = "y" ,Y = y,Name="bin1",Jitter=0.1,BoxPoints=StyleParam.BoxPoints.All, UseDefaults = false); - Chart.BoxPlot(X = "y'",Y = y,Name="bin2",Jitter=0.1,BoxPoints=StyleParam.BoxPoints.All, UseDefaults = false); - ] - |> Chart.combine + Chart.Point(x = x, y = y, UseDefaults = false) + |> Chart.withYAxisStyle("This title must") + + Chart.Line(x = x, y = y, UseDefaults = false) + |> Chart.withYAxisStyle("be set on the",ZeroLine=false) + + Chart.Spline(x = x, y = y, UseDefaults = false) + |> Chart.withYAxisStyle("respective subplots",ZeroLine=false) ] - |> Chart.SingleStack() - |> Chart.withSize(1000,1000) + |> Chart.SingleStack(Pattern = StyleParam.LayoutGridPattern.Coupled) + //move xAxis to bottom and increase spacing between plots by using the withLayoutGridStyle function + |> Chart.withLayoutGridStyle(XSide=StyleParam.LayoutGridXSide.Bottom,YGap= 0.1) + |> Chart.withTitle("Hi i am the new SingleStackChart") + |> Chart.withXAxisStyle("im the shared xAxis") |> Chart.show 0 \ No newline at end of file diff --git a/tests/CoreTests/CoreTests/CoreTests.fsproj b/tests/CoreTests/CoreTests/CoreTests.fsproj index 69c915b0..3466c51c 100644 --- a/tests/CoreTests/CoreTests/CoreTests.fsproj +++ b/tests/CoreTests/CoreTests/CoreTests.fsproj @@ -46,6 +46,7 @@ + diff --git a/tests/CoreTests/CoreTests/FeatureAdditions/Fix_3d_GridPosition.fs b/tests/CoreTests/CoreTests/FeatureAdditions/Fix_3d_GridPosition.fs new file mode 100644 index 00000000..b04be19e --- /dev/null +++ b/tests/CoreTests/CoreTests/FeatureAdditions/Fix_3d_GridPosition.fs @@ -0,0 +1,34 @@ +module CoreTests.Fix_3d_GridPosition + +open Expecto +open Plotly.NET +open Plotly.NET.LayoutObjects +open Plotly.NET.TraceObjects + +open TestUtils.HtmlCodegen +open Fix_3d_GridPosition + +// https://github.com/plotly/Plotly.NET/issues/413 + +module ``Remove all existing subplots from individual charts on grid creation #413`` = + + [] + let ``Add subplot titles`` = + testList "FeatureAddition.Fix 3D chart position in Grid" [ + test "2x2 3d charts data" { + """var data = [{"type":"scatter3d","mode":"markers","x":[1],"y":[3],"z":[2],"marker":{},"line":{},"scene":"scene"},{"type":"scatter3d","mode":"markers","x":[1],"y":[3],"z":[2],"marker":{},"line":{},"scene":"scene2"},{"type":"scatter3d","mode":"markers","x":[1],"y":[3],"z":[2],"marker":{},"line":{},"scene":"scene3"},{"type":"scatter3d","mode":"markers","x":[1],"y":[3],"z":[2],"marker":{},"line":{},"scene":"scene4"}];""" + |> chartGeneratedContains ``Remove all existing subplots from individual charts on grid creation #413``.``2x2 grid with only 3D charts and correct scene positioning`` + } + test "2x2 3d charts layout" { + """var layout = {"scene":{"camera":{"projection":{"type":"perspective"}},"domain":{"row":0,"column":0}},"scene2":{"camera":{"projection":{"type":"perspective"}},"domain":{"row":0,"column":1}},"scene3":{"camera":{"projection":{"type":"perspective"}},"domain":{"row":1,"column":0}},"scene4":{"camera":{"projection":{"type":"perspective"}},"domain":{"row":1,"column":1}},"annotations":[{"x":0.22222222222222224,"y":1.0,"showarrow":false,"text":"1","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"},{"x":0.7777777777777778,"y":1.0,"showarrow":false,"text":"2","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"},{"x":0.22222222222222224,"y":0.4117647058823529,"showarrow":false,"text":"3","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"},{"x":0.7777777777777778,"y":0.4117647058823529,"showarrow":false,"text":"4","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"}],"grid":{"rows":2,"columns":2,"roworder":"top to bottom","pattern":"independent"}};""" + |> chartGeneratedContains ``Remove all existing subplots from individual charts on grid creation #413``.``2x2 grid with only 3D charts and correct scene positioning`` + } + test "2x2 3d charts ignores additional scenes data" { + """var data = [{"type":"scatter3d","mode":"markers","x":[1],"y":[3],"z":[2],"marker":{},"line":{},"scene":"scene"},{"type":"scatter3d","mode":"markers","x":[1],"y":[3],"z":[2],"marker":{},"line":{},"scene":"scene2"},{"type":"scatter3d","mode":"markers","x":[1],"y":[3],"z":[2],"marker":{},"line":{},"scene":"scene3"},{"type":"scatter3d","mode":"markers","x":[1],"y":[3],"z":[2],"marker":{},"line":{},"scene":"scene4"}];""" + |> chartGeneratedContains ``Remove all existing subplots from individual charts on grid creation #413``.``2x2 grid chart creation ignores other scenes`` + } + test "2x2 3d charts ignores additional scenes layout" { + """var layout = {"scene2":{"camera":{"projection":{"type":"perspective"}},"domain":{"row":0,"column":1}},"scene":{"camera":{"projection":{"type":"perspective"}},"domain":{"row":0,"column":0}},"scene3":{"camera":{"projection":{"type":"perspective"}},"domain":{"row":1,"column":0}},"scene4":{"camera":{"projection":{"type":"perspective"}},"domain":{"row":1,"column":1}},"annotations":[{"x":0.22222222222222224,"y":1.0,"showarrow":false,"text":"1","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"},{"x":0.7777777777777778,"y":1.0,"showarrow":false,"text":"2","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"},{"x":0.22222222222222224,"y":0.4117647058823529,"showarrow":false,"text":"3","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"},{"x":0.7777777777777778,"y":0.4117647058823529,"showarrow":false,"text":"4","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"}],"grid":{"rows":2,"columns":2,"roworder":"top to bottom","pattern":"independent"}};""" + |> chartGeneratedContains ``Remove all existing subplots from individual charts on grid creation #413``.``2x2 grid chart creation ignores other scenes`` + } + ] \ No newline at end of file diff --git a/tests/CoreTests/CoreTests/FeatureAdditions/Grid_SubPlotTitles.fs b/tests/CoreTests/CoreTests/FeatureAdditions/Grid_SubPlotTitles.fs index 93c19d43..bcb68542 100644 --- a/tests/CoreTests/CoreTests/FeatureAdditions/Grid_SubPlotTitles.fs +++ b/tests/CoreTests/CoreTests/FeatureAdditions/Grid_SubPlotTitles.fs @@ -34,7 +34,7 @@ module ``Add logic for positioning subplot titles in LayoutGrid #388`` = |> chartGeneratedContains ``Add logic for positioning subplot titles in LayoutGrid #388``.``singlestack with different subplot types and subplot titles`` } test "singlestack with different subplot types layout" { - """var layout = {"xaxis":{},"yaxis":{},"scene":{"camera":{"projection":{"type":"perspective"}},"domain":{"row":1,"column":0}},"scene2":{"camera":{"projection":{"type":"perspective"}},"domain":{"row":1,"column":0}},"polar3":{"domain":{"row":2,"column":0}},"geo4":{"domain":{"row":3,"column":0}},"annotations":[{"x":0.5,"y":0.9999999999999999,"showarrow":false,"text":"2D Cartesian","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"},{"x":0.5,"y":0.7297297297297296,"showarrow":false,"text":"3D Cartesian","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"},{"x":0.5,"y":0.4594594594594594,"showarrow":false,"text":"Polar","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"},{"x":0.5,"y":0.18918918918918914,"showarrow":false,"text":"Geo","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"}],"grid":{"rows":4,"columns":1,"roworder":"top to bottom","pattern":"independent"}};""" + """var layout = {"xaxis":{},"yaxis":{},"scene2":{"camera":{"projection":{"type":"perspective"}},"domain":{"row":1,"column":0}},"polar3":{"domain":{"row":2,"column":0}},"geo4":{"domain":{"row":3,"column":0}},"annotations":[{"x":0.5,"y":0.9999999999999999,"showarrow":false,"text":"2D Cartesian","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"},{"x":0.5,"y":0.7297297297297296,"showarrow":false,"text":"3D Cartesian","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"},{"x":0.5,"y":0.4594594594594594,"showarrow":false,"text":"Polar","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"},{"x":0.5,"y":0.18918918918918914,"showarrow":false,"text":"Geo","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"}],"grid":{"rows":4,"columns":1,"roworder":"top to bottom","pattern":"independent"}};""" |> chartGeneratedContains ``Add logic for positioning subplot titles in LayoutGrid #388``.``singlestack with different subplot types and subplot titles`` } test "chart grid with all subplot types data" { @@ -42,7 +42,7 @@ module ``Add logic for positioning subplot titles in LayoutGrid #388`` = |> chartGeneratedContains ``Add logic for positioning subplot titles in LayoutGrid #388``.``chart grid with all subplot types and subplot titles`` } test "chart grid with all subplot types layout" { - """var layout = {"xaxis":{},"yaxis":{},"scene":{"camera":{"projection":{"type":"perspective"}},"domain":{"row":0,"column":1}},"scene2":{"camera":{"projection":{"type":"perspective"}},"domain":{"row":0,"column":1}},"polar3":{"domain":{"row":0,"column":2}},"geo4":{"domain":{"row":1,"column":0}},"mapbox":{"style":"open-street-map","domain":{"row":1,"column":1}},"mapbox5":{"style":"open-street-map","domain":{"row":1,"column":1}},"ternary6":{"domain":{"row":1,"column":2}},"xaxis7":{},"yaxis7":{},"smith9":{"domain":{"row":2,"column":2}},"xaxis10":{},"yaxis10":{},"annotations":[{"x":0.14285714285714288,"y":1.045,"font":{"size":20.0},"showarrow":false,"text":"Point","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"},{"x":0.5,"y":1.045,"font":{"size":20.0},"showarrow":false,"text":"Point3D","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"},{"x":0.8571428571428572,"y":1.045,"font":{"size":20.0},"showarrow":false,"text":"PointPolar","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"},{"x":0.14285714285714288,"y":0.7592857142857142,"font":{"size":20.0},"showarrow":false,"text":"PointGeo","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"},{"x":0.5,"y":0.7592857142857142,"font":{"size":20.0},"showarrow":false,"text":"PointMapbox","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"},{"x":0.8571428571428572,"y":0.7592857142857142,"font":{"size":20.0},"showarrow":false,"text":"PointTernary","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"},{"x":0.14285714285714288,"y":0.47357142857142853,"font":{"size":20.0},"showarrow":false,"text":"ContourCarpet","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"},{"x":0.5,"y":0.47357142857142853,"font":{"size":20.0},"showarrow":false,"text":"Pie","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"},{"x":0.8571428571428572,"y":0.47357142857142853,"font":{"size":20.0},"showarrow":false,"text":"BubbleSmith","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"},{"x":0.14285714285714288,"y":0.18785714285714283,"font":{"size":20.0},"showarrow":false,"text":"Combined BoxPlot","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"}],"grid":{"rows":4,"columns":3,"roworder":"top to bottom","pattern":"independent","ygap":0.5},"width":1000,"height":1000};""" + """var layout = {"xaxis":{},"yaxis":{},"scene2":{"camera":{"projection":{"type":"perspective"}},"domain":{"row":0,"column":1}},"polar3":{"domain":{"row":0,"column":2}},"geo4":{"domain":{"row":1,"column":0}},"mapbox5":{"style":"open-street-map","domain":{"row":1,"column":1}},"ternary6":{"domain":{"row":1,"column":2}},"xaxis7":{},"yaxis7":{},"smith9":{"domain":{"row":2,"column":2}},"xaxis10":{},"yaxis10":{},"annotations":[{"x":0.14285714285714288,"y":1.045,"font":{"size":20.0},"showarrow":false,"text":"Point","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"},{"x":0.5,"y":1.045,"font":{"size":20.0},"showarrow":false,"text":"Point3D","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"},{"x":0.8571428571428572,"y":1.045,"font":{"size":20.0},"showarrow":false,"text":"PointPolar","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"},{"x":0.14285714285714288,"y":0.7592857142857142,"font":{"size":20.0},"showarrow":false,"text":"PointGeo","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"},{"x":0.5,"y":0.7592857142857142,"font":{"size":20.0},"showarrow":false,"text":"PointMapbox","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"},{"x":0.8571428571428572,"y":0.7592857142857142,"font":{"size":20.0},"showarrow":false,"text":"PointTernary","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"},{"x":0.14285714285714288,"y":0.47357142857142853,"font":{"size":20.0},"showarrow":false,"text":"ContourCarpet","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"},{"x":0.5,"y":0.47357142857142853,"font":{"size":20.0},"showarrow":false,"text":"Pie","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"},{"x":0.8571428571428572,"y":0.47357142857142853,"font":{"size":20.0},"showarrow":false,"text":"BubbleSmith","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"},{"x":0.14285714285714288,"y":0.18785714285714283,"font":{"size":20.0},"showarrow":false,"text":"Combined BoxPlot","xanchor":"center","xref":"paper","yanchor":"bottom","yref":"paper"}],"grid":{"rows":4,"columns":3,"roworder":"top to bottom","pattern":"independent","ygap":0.5},"width":1000,"height":1000};""" |> chartGeneratedContains ``Add logic for positioning subplot titles in LayoutGrid #388``.``chart grid with all subplot types and subplot titles`` } ] \ No newline at end of file diff --git a/tests/CoreTests/CoreTests/HTMLCodegen/ChartLayout.fs b/tests/CoreTests/CoreTests/HTMLCodegen/ChartLayout.fs index d9d275ad..31757fcd 100644 --- a/tests/CoreTests/CoreTests/HTMLCodegen/ChartLayout.fs +++ b/tests/CoreTests/CoreTests/HTMLCodegen/ChartLayout.fs @@ -252,7 +252,7 @@ let ``Multicharts and subplots`` = |> chartGeneratedContains subPlotChart ); testCase "Subplot grids layout" ( fun () -> - """var layout = {"xaxis":{"title":{"text":"x1"}},"yaxis":{"title":{"text":"y1"}},"xaxis2":{"title":{"text":"x2"}},"yaxis2":{"title":{"text":"y2"}},"xaxis3":{"title":{"text":"x3"}},"yaxis3":{"title":{"text":"y3"}},"xaxis4":{"title":{"text":"x4"}},"yaxis4":{"title":{"text":"y4"}},"annotations":[],"grid":{"rows":2,"columns":2,"roworder":"top to bottom","pattern":"independent"}};""" + """var layout = {"yaxis":{"title":{"text":"y1"}},"xaxis":{"title":{"text":"x1"}},"yaxis2":{"title":{"text":"y2"}},"xaxis2":{"title":{"text":"x2"}},"yaxis3":{"title":{"text":"y3"}},"xaxis3":{"title":{"text":"x3"}},"yaxis4":{"title":{"text":"y4"}},"xaxis4":{"title":{"text":"x4"}},"annotations":[],"grid":{"rows":2,"columns":2,"roworder":"top to bottom","pattern":"independent"}};""" |> chartGeneratedContains subPlotChart ); testCase "MultiTrace Subplot grid data" ( fun () -> @@ -260,7 +260,7 @@ let ``Multicharts and subplots`` = |> chartGeneratedContains multiTraceGrid ); testCase "MultiTrace Subplot grid layout" ( fun () -> - """var layout = {"xaxis":{},"yaxis":{},"scene":{"camera":{"projection":{"type":"perspective"}},"domain":{"row":0,"column":1}},"scene2":{"camera":{"projection":{"type":"perspective"}},"domain":{"row":0,"column":1}},"polar3":{"domain":{"row":0,"column":2}},"geo4":{"domain":{"row":1,"column":0}},"mapbox":{"style":"open-street-map","domain":{"row":1,"column":1}},"mapbox5":{"style":"open-street-map","domain":{"row":1,"column":1}},"ternary6":{"domain":{"row":1,"column":2}},"xaxis7":{},"yaxis7":{},"smith9":{"domain":{"row":2,"column":2}},"xaxis10":{},"yaxis10":{},"annotations":[],"grid":{"rows":4,"columns":3,"roworder":"top to bottom","pattern":"independent"},"width":1000,"height":1000};""" + """var layout = {"xaxis":{},"yaxis":{},"scene2":{"camera":{"projection":{"type":"perspective"}},"domain":{"row":0,"column":1}},"polar3":{"domain":{"row":0,"column":2}},"geo4":{"domain":{"row":1,"column":0}},"mapbox5":{"style":"open-street-map","domain":{"row":1,"column":1}},"ternary6":{"domain":{"row":1,"column":2}},"xaxis7":{},"yaxis7":{},"smith9":{"domain":{"row":2,"column":2}},"xaxis10":{},"yaxis10":{},"annotations":[],"grid":{"rows":4,"columns":3,"roworder":"top to bottom","pattern":"independent"},"width":1000,"height":1000};""" |> chartGeneratedContains multiTraceGrid ); testCase "Single Stack data" ( fun () -> @@ -268,7 +268,7 @@ let ``Multicharts and subplots`` = |> chartGeneratedContains singleStackChart ); testCase "Single Stack layout" ( fun () -> - """var layout = {"yaxis":{"title":{"text":"This title must"}},"xaxis":{"title":{"text":"im the shared xAxis"}},"xaxis2":{},"yaxis2":{"title":{"text":"be set on the"},"zeroline":false},"xaxis3":{},"yaxis3":{"title":{"text":"respective subplots"},"zeroline":false},"annotations":[],"grid":{"rows":3,"columns":1,"roworder":"top to bottom","pattern":"coupled","ygap":0.1,"xside":"bottom"},"title":{"text":"Hi i am the new SingleStackChart"}};""" + """var layout = {"xaxis":{"title":{"text":"im the shared xAxis"}},"yaxis":{"title":{"text":"This title must"}},"xaxis2":{},"yaxis2":{"title":{"text":"be set on the"},"zeroline":false},"xaxis3":{},"yaxis3":{"title":{"text":"respective subplots"},"zeroline":false},"annotations":[],"grid":{"rows":3,"columns":1,"roworder":"top to bottom","pattern":"coupled","ygap":0.1,"xside":"bottom"},"title":{"text":"Hi i am the new SingleStackChart"}};""" |> chartGeneratedContains singleStackChart ); @@ -277,7 +277,7 @@ let ``Multicharts and subplots`` = |> chartGeneratedContains multiTraceSingleStack ); testCase "MultiTrace Single Stack layout" ( fun () -> - """var layout = {"xaxis":{},"yaxis":{},"ternary2":{"domain":{"row":1,"column":0}},"xaxis3":{},"yaxis3":{},"scene":{"camera":{"projection":{"type":"perspective"}},"domain":{"row":3,"column":0}},"scene4":{"camera":{"projection":{"type":"perspective"}},"domain":{"row":3,"column":0}},"mapbox":{"style":"open-street-map","domain":{"row":4,"column":0}},"mapbox5":{"style":"open-street-map","domain":{"row":4,"column":0}},"xaxis6":{},"yaxis6":{},"annotations":[],"grid":{"rows":6,"columns":1,"roworder":"top to bottom","pattern":"independent"},"width":1000,"height":1000};""" + """var layout = {"xaxis":{},"yaxis":{},"ternary2":{"domain":{"row":1,"column":0}},"xaxis3":{},"yaxis3":{},"scene4":{"camera":{"projection":{"type":"perspective"}},"domain":{"row":3,"column":0}},"mapbox5":{"style":"open-street-map","domain":{"row":4,"column":0}},"xaxis6":{},"yaxis6":{},"annotations":[],"grid":{"rows":6,"columns":1,"roworder":"top to bottom","pattern":"independent"},"width":1000,"height":1000};""" |> chartGeneratedContains multiTraceSingleStack ); ]